Merge mainline into pub_dependency_services (#3301)
diff --git a/analysis_options.yaml b/analysis_options.yaml index 9cefb58..6177eba 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml
@@ -1,4 +1,4 @@ -include: package:pedantic/analysis_options.yaml +include: package:lints/recommended.yaml analyzer: errors: @@ -12,53 +12,27 @@ linter: rules: - avoid_catching_errors - - avoid_function_literals_in_foreach_calls - avoid_private_typedef_functions - avoid_redundant_argument_values - - avoid_renaming_method_parameters - avoid_returning_null_for_future - - avoid_returning_null_for_void - avoid_unused_constructor_parameters - avoid_void_async - - await_only_futures - - camel_case_types - cancel_subscriptions - - control_flow_in_finally - directives_ordering - - empty_statements - - file_names - - implementation_imports - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - literal_only_boolean_expressions - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - no_runtimeType_toString - - non_constant_identifier_names - only_throw_errors - - overridden_fields - package_api_docs - - package_names - - package_prefixed_library_names - prefer_asserts_in_initializer_lists - prefer_const_declarations - - prefer_function_declarations_over_variables - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_is_not_operator - - prefer_null_aware_operators - prefer_relative_imports - - prefer_typing_uninitialized_variables - - prefer_void_to_null + - prefer_single_quotes - sort_pub_dependencies - test_types_in_equals - throw_in_finally - - unnecessary_brace_in_string_interps - - unnecessary_getters_setters + - unawaited_futures - unnecessary_lambdas - unnecessary_null_aware_assignments - - unnecessary_overrides - unnecessary_parenthesis - unnecessary_statements - - unnecessary_string_interpolations - - void_checks
diff --git a/bin/dependency_services.dart b/bin/dependency_services.dart new file mode 100644 index 0000000..1e7b4c1 --- /dev/null +++ b/bin/dependency_services.dart
@@ -0,0 +1,105 @@ +// Copyright (c) 2021, 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. + +/// Support for automated upgrades. +/// +/// For now this is not a finalized interface. Don't rely on this. +import 'dart:async'; + +import 'package:args/args.dart'; +import 'package:args/command_runner.dart'; +import 'package:pub/src/command.dart'; +import 'package:pub/src/command/dependency_services.dart'; +import 'package:pub/src/exit_codes.dart' as exit_codes; +import 'package:pub/src/io.dart'; +import 'package:pub/src/log.dart' as log; + +class DependencyServicesCommandRunner extends CommandRunner<int> + implements PubTopLevel { + @override + String? get directory => argResults['directory']; + + @override + bool get captureStackChains { + return argResults['trace'] || + argResults['verbose'] || + argResults['verbosity'] == 'all'; + } + + @override + bool get trace => argResults['trace']; + + ArgResults? _argResults; + + /// The top-level options parsed by the command runner. + @override + ArgResults get argResults { + final a = _argResults; + if (a == null) { + throw StateError( + 'argResults cannot be used before Command.run is called.'); + } + return a; + } + + DependencyServicesCommandRunner() + : super('dependency_services', 'Support for automatic upgrades', + usageLineLength: lineLength) { + argParser.addFlag('version', negatable: false, help: 'Print pub version.'); + argParser.addFlag('trace', + help: 'Print debugging information when an error occurs.'); + argParser + .addOption('verbosity', help: 'Control output verbosity.', allowed: [ + 'error', + 'warning', + 'normal', + 'io', + 'solver', + 'all' + ], allowedHelp: { + 'error': 'Show only errors.', + 'warning': 'Show only errors and warnings.', + 'normal': 'Show errors, warnings, and user messages.', + 'io': 'Also show IO operations.', + 'solver': 'Show steps during version resolution.', + 'all': 'Show all output including internal tracing messages.' + }); + argParser.addFlag('verbose', + abbr: 'v', negatable: false, help: 'Shortcut for "--verbosity=all".'); + argParser.addOption( + 'directory', + abbr: 'C', + help: 'Run the subcommand in the directory<dir>.', + defaultsTo: '.', + valueHelp: 'dir', + ); + + addCommand(DependencyServicesListCommand()); + addCommand(DependencyServicesReportCommand()); + addCommand(DependencyServicesApplyCommand()); + } + + @override + Future<int> run(Iterable<String> args) async { + try { + _argResults = parse(args); + return await runCommand(argResults) ?? exit_codes.SUCCESS; + } on UsageException catch (error) { + log.exception(error); + return exit_codes.USAGE; + } + } + + @override + void printUsage() { + log.message(usage); + } + + @override + log.Verbosity get verbosity => log.Verbosity.normal; +} + +Future<void> main(List<String> arguments) async { + await flushThenExit(await DependencyServicesCommandRunner().run(arguments)); +}
diff --git a/bin/pub.dart b/bin/pub.dart index 926db85..f133a0f 100644 --- a/bin/pub.dart +++ b/bin/pub.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/command_runner.dart'; import 'package:pub/src/io.dart';
diff --git a/doc/repository-spec-v2.md b/doc/repository-spec-v2.md index 6db7763..6ddfd0f 100644 --- a/doc/repository-spec-v2.md +++ b/doc/repository-spec-v2.md
@@ -227,7 +227,7 @@ "replacedBy": "<package>", /* optional field, if isDiscontinued == true */ "latest": { "version": "<version>", - "isRetracted": true || false, /* optional field, false if omitted */ + "retracted": true || false, /* optional field, false if omitted */ "archive_url": "https://.../archive.tar.gz", "pubspec": { /* pubspec contents as JSON object */ @@ -236,7 +236,7 @@ "versions": [ { "version": "<package>", - "isRetracted": true || false, /* optional field, false if omitted */ + "retracted": true || false, /* optional field, false if omitted */ "archive_url": "https://.../archive.tar.gz", "pubspec": { /* pubspec contents as JSON object */ @@ -371,7 +371,9 @@ archive size, or enforce any other repository specific constraints. This upload flow allows for archives to be uploaded directly to a signed POST -URL for S3, GCS or similar blob storage service. Both the +URL for [S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/HTTPPOSTExamples.html), +[GCS](https://cloud.google.com/storage/docs/xml-api/post-object-forms) or +similar blob storage service. Both the `<multipart-upload-url>` and `<finalize-upload-url>` is allowed to contain query-string parameters, and both of these URLs need only be temporary.
diff --git a/lib/pub.dart b/lib/pub.dart index b78cbca..71de9d6 100644 --- a/lib/pub.dart +++ b/lib/pub.dart
@@ -2,17 +2,28 @@ // 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. -// @dart=2.10 - import 'package:args/command_runner.dart'; import 'src/command_runner.dart'; import 'src/pub_embeddable_command.dart'; export 'src/executable.dart' - show getExecutableForCommand, CommandResolutionFailedException; + show + getExecutableForCommand, + CommandResolutionFailedException, + CommandResolutionIssue, + DartExecutableWithPackageConfig; +export 'src/pub_embeddable_command.dart' show PubAnalytics; /// Returns a [Command] for pub functionality that can be used by an embedding /// CommandRunner. -Command<int> pubCommand() => PubEmbeddableCommand(); +/// +/// If [analytics] is given, pub will use that analytics instance to send +/// statistics about resolutions. +/// +/// [isVerbose] should return `true` (after argument resolution) if the +/// embedding top-level is in verbose mode. +Command<int> pubCommand( + {PubAnalytics? analytics, required bool Function() isVerbose}) => + PubEmbeddableCommand(analytics, isVerbose); /// Support for the `pub` toplevel command. @Deprecated('Use [pubCommand] instead.')
diff --git a/lib/src/authentication/client.dart b/lib/src/authentication/client.dart index 3de5b2e..a6001ec 100644 --- a/lib/src/authentication/client.dart +++ b/lib/src/authentication/client.dart
@@ -2,15 +2,12 @@ // 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. -// @dart=2.11 - import 'dart:io'; import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; -import '../exceptions.dart'; import '../http.dart'; import '../log.dart' as log; import '../system_cache.dart'; @@ -24,14 +21,17 @@ /// Constructs Http client wrapper that injects `authorization` header to /// requests and handles authentication errors. /// - /// [credential] might be `null`. In that case `authorization` header will not + /// [_credential] might be `null`. In that case `authorization` header will not /// be injected to requests. - _AuthenticatedClient(this._inner, this.credential); + _AuthenticatedClient(this._inner, this._credential); final http.BaseClient _inner; /// Authentication scheme that could be used for authenticating requests. - final Credential credential; + final Credential? _credential; + + /// Detected that [_credential] are invalid, happens when server responds 401. + bool _detectInvalidCredentials = false; @override Future<http.StreamedResponse> send(http.BaseRequest request) async { @@ -42,20 +42,21 @@ // to given serverBaseUrl. Otherwise credential leaks might ocurr when // archive_url hosted on 3rd party server that should not receive // credentials of the first party. - if (credential != null && - credential.canAuthenticate(request.url.toString())) { + if (_credential != null && + _credential!.canAuthenticate(request.url.toString())) { request.headers[HttpHeaders.authorizationHeader] = - await credential.getAuthorizationHeaderValue(); + await _credential!.getAuthorizationHeaderValue(); } try { final response = await _inner.send(request); if (response.statusCode == 401) { + _detectInvalidCredentials = true; _throwAuthException(response); } return response; } on PubHttpException catch (e) { - if (e.response?.statusCode == 403) { + if (e.response.statusCode == 403) { _throwAuthException(e.response); } rethrow; @@ -68,16 +69,18 @@ /// /// [RFC]: https://datatracker.ietf.org/doc/html/rfc7235#section-4.1 void _throwAuthException(http.BaseResponse response) { - String serverMessage; + String? serverMessage; if (response.headers.containsKey(HttpHeaders.wwwAuthenticateHeader)) { try { - final header = response.headers[HttpHeaders.wwwAuthenticateHeader]; + final header = response.headers[HttpHeaders.wwwAuthenticateHeader]!; final challenge = AuthenticationChallenge.parseHeader(header) .firstWhereOrNull((challenge) => challenge.scheme == 'bearer' && challenge.parameters['realm'] == 'pub' && challenge.parameters['message'] != null); - serverMessage = challenge?.parameters['message']; + if (challenge != null) { + serverMessage = challenge.parameters['message']; + } } on FormatException { // Ignore errors might be caused when parsing invalid header values } @@ -101,7 +104,7 @@ const AuthenticationException(this.statusCode, this.serverMessage); final int statusCode; - final String serverMessage; + final String? serverMessage; @override String toString() { @@ -124,31 +127,17 @@ Future<T> Function(http.Client) fn, ) async { final credential = systemCache.tokenStore.findCredential(hostedUrl); - final http.Client client = _AuthenticatedClient(httpClient, credential); + final client = _AuthenticatedClient(httpClient, credential); try { return await fn(client); - } on AuthenticationException catch (error) { - String message; - - if (error.statusCode == 401) { - if (systemCache.tokenStore.removeCredential(hostedUrl)) { + } finally { + if (client._detectInvalidCredentials) { + // try to remove the credential, if we detected that it is invalid! + final removed = systemCache.tokenStore.removeCredential(hostedUrl); + if (removed) { log.warning('Invalid token for $hostedUrl deleted.'); } - message = '$hostedUrl package repository requested authentication! ' - 'You can provide credential using:\n' - ' pub token add $hostedUrl'; } - if (error.statusCode == 403) { - message = 'Insufficient permissions to the resource in $hostedUrl ' - 'package repository. You can modify credential using:\n' - ' pub token add $hostedUrl'; - } - - if (error.serverMessage?.isNotEmpty == true) { - message += '\n${error.serverMessage}'; - } - - throw DataException(message); } }
diff --git a/lib/src/authentication/credential.dart b/lib/src/authentication/credential.dart index a44cc91..e1dfc79 100644 --- a/lib/src/authentication/credential.dart +++ b/lib/src/authentication/credential.dart
@@ -2,12 +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. -// @dart=2.11 - import 'dart:io'; -import 'package:meta/meta.dart'; - import '../exceptions.dart'; import '../source/hosted.dart'; @@ -27,10 +23,10 @@ class Credential { /// Internal constructor that's only used by [fromJson]. Credential._internal({ - @required this.url, - @required this.unknownFields, - @required this.token, - @required this.env, + required this.url, + required this.unknownFields, + required this.token, + required this.env, }); /// Create credential that stores clear text token. @@ -62,7 +58,7 @@ /// doesn't contains [key]. /// /// Throws [FormatException] if value type is not [String]. - String _string(String key) { + String? _string(String key) { if (json.containsKey(key)) { if (json[key] is! String) { throw FormatException('Provided $key value should be string'); @@ -84,10 +80,10 @@ final Uri url; /// Authentication token value - final String token; + final String? token; /// Environment variable name that stores token value - final String env; + final String? env; /// Unknown fields found in pub-tokens.json. The fields might be created by the /// future version of pub tool. We don't want to override them when using the @@ -114,13 +110,14 @@ Future<String> getAuthorizationHeaderValue() { if (!isValid()) { throw DataException( - 'Saved credential for $url pub repository is not supported by current ' - 'version of Dart SDK.', + 'Saved credential for "$url" pub repository is not supported by ' + 'current version of Dart SDK.', ); } - if (env != null) { - final value = Platform.environment[env]; + final environment = env; + if (environment != null) { + final value = Platform.environment[environment]; if (value == null) { throw DataException( 'Saved credential for "$url" pub repository requires environment '
diff --git a/lib/src/authentication/token_store.dart b/lib/src/authentication/token_store.dart index 24f70fc..3ef948d 100644 --- a/lib/src/authentication/token_store.dart +++ b/lib/src/authentication/token_store.dart
@@ -2,12 +2,12 @@ // 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. -// @dart=2.11 - import 'dart:convert'; +import 'dart:io'; import 'package:path/path.dart' as path; +import '../exceptions.dart'; import '../io.dart'; import '../log.dart' as log; import 'credential.dart'; @@ -17,7 +17,7 @@ TokenStore(this.configDir); /// Cache directory. - final String configDir; + final String? configDir; /// List of saved authentication tokens. /// @@ -28,9 +28,9 @@ /// Reads "pub-tokens.json" and parses / deserializes it into list of /// [Credential]. List<Credential> _loadCredentials() { - final result = List<Credential>.empty(growable: true); + final result = <Credential>[]; final path = _tokensFile; - if (!fileExists(path)) { + if (path == null || !fileExists(path)) { return result; } @@ -90,11 +90,20 @@ return result; } + Never missingConfigDir() { + final variable = Platform.isWindows ? '%APPDATA%' : r'$HOME'; + throw DataException('No config dir found. Check that $variable is set'); + } + /// Writes [credentials] into "pub-tokens.json". void _saveCredentials(List<Credential> credentials) { - ensureDir(path.dirname(_tokensFile)); + final tokensFile = _tokensFile; + if (tokensFile == null) { + missingConfigDir(); + } + ensureDir(path.dirname(tokensFile)); writeTextFile( - _tokensFile, + tokensFile, jsonEncode(<String, dynamic>{ 'version': 1, 'hosted': credentials.map((it) => it.toJson()).toList(), @@ -134,8 +143,8 @@ /// Returns [Credential] for authenticating given [hostedUrl] or `null` if no /// matching credential is found. - Credential findCredential(Uri hostedUrl) { - Credential matchedCredential; + Credential? findCredential(Uri hostedUrl) { + Credential? matchedCredential; for (final credential in credentials) { if (credential.url == hostedUrl && credential.isValid()) { if (matchedCredential == null) { @@ -161,10 +170,22 @@ /// Deletes pub-tokens.json file from the disk. void deleteTokensFile() { - deleteEntry(_tokensFile); - log.message('pub-tokens.json is deleted.'); + final tokensFile = _tokensFile; + if (tokensFile == null) { + missingConfigDir(); + } else if (!fileExists(tokensFile)) { + log.message('No credentials file found at "$tokensFile"'); + } else { + deleteEntry(tokensFile); + log.message('pub-tokens.json is deleted.'); + } } /// Full path to the "pub-tokens.json" file. - String get _tokensFile => path.join(configDir, 'pub-tokens.json'); + /// + /// `null` if no config directory could be found. + String? get _tokensFile { + var dir = configDir; + return dir == null ? null : path.join(dir, 'pub-tokens.json'); + } }
diff --git a/lib/src/command.dart b/lib/src/command.dart index cd4a524..4d02c8a 100644 --- a/lib/src/command.dart +++ b/lib/src/command.dart
@@ -2,15 +2,15 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; import 'package:args/args.dart'; import 'package:args/command_runner.dart'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; +import 'package:path/path.dart' as p; import 'authentication/token_store.dart'; import 'command_runner.dart'; @@ -46,15 +46,27 @@ /// of subcommands. Only leaf commands are ever actually invoked. If a command /// has subcommands, then one of those must always be chosen. abstract class PubCommand extends Command<int> { - String get directory => argResults['directory'] ?? _pubTopLevel.directory; + @override + ArgResults get argResults { + final a = super.argResults; + if (a == null) { + throw StateError( + 'argResults cannot be used before Command.run is called.'); + } + return a; + } - SystemCache get cache => _cache ??= SystemCache(isOffline: isOffline); + String get directory => + (argResults.options.contains('directory') + ? argResults['directory'] + : null) ?? + _pubTopLevel.directory; - SystemCache _cache; + late final SystemCache cache = SystemCache(isOffline: isOffline); GlobalPackages get globals => _globals ??= GlobalPackages(cache); - GlobalPackages _globals; + GlobalPackages? _globals; TokenStore get tokenStore => cache.tokenStore; @@ -62,12 +74,10 @@ /// /// This will load the pubspec and fail with an error if the current directory /// is not a package. - Entrypoint get entrypoint => _entrypoint ??= Entrypoint(directory, cache); - - Entrypoint _entrypoint; + late final Entrypoint entrypoint = Entrypoint(directory, cache); /// The URL for web documentation for this command. - String get docUrl => null; + String? get docUrl => null; /// Override this and return `false` to disallow trailing options from being /// parsed after a non-option argument is parsed. @@ -76,11 +86,9 @@ // Lazily initialize the parser because the superclass constructor requires // it but we want to initialize it based on [allowTrailingOptions]. @override - ArgParser get argParser => _argParser ??= ArgParser( + late final ArgParser argParser = ArgParser( allowTrailingOptions: allowTrailingOptions, usageLineLength: lineLength); - ArgParser _argParser; - /// Override this to use offline-only sources instead of hitting the network. /// /// This will only be called before the [SystemCache] is created. After that, @@ -88,7 +96,7 @@ bool get isOffline => false; @override - String get usageFooter { + String? get usageFooter { if (docUrl == null) return null; return 'See $docUrl for detailed documentation.'; } @@ -98,35 +106,41 @@ /// The first command in the command chain. Command get _topCommand { - var command = this; - while (command.parent != null) { + Command current = this; + while (true) { + var parent = current.parent; + if (parent == null) return current; + current = parent; + } + } + + PubEmbeddableCommand? get _pubEmbeddableCommand { + Command? command = this; + while (command is! PubEmbeddableCommand) { + if (command == null) { + return null; + } command = command.parent; } + return command; } - PubEmbeddableCommand get _pubEmbeddableCommand { - var command = this; - while (command != null && command is! PubEmbeddableCommand) { - command = command.parent; - } - return command; - } + PubTopLevel get _pubTopLevel => + _pubEmbeddableCommand ?? runner as PubTopLevel; - PubTopLevel get _pubTopLevel { - return _pubEmbeddableCommand ?? (runner as PubCommandRunner); - } + PubAnalytics? get analytics => _pubEmbeddableCommand?.analytics; @override String get invocation { - var command = this; + PubCommand? command = this; var names = []; do { - names.add(command.name); - command = command.parent; + names.add(command?.name); + command = command?.parent as PubCommand?; } while (command != null); return [ - runner.executableName, + runner!.executableName, ...names.reversed, argumentsDescription, ].join(' '); @@ -143,7 +157,7 @@ /// when exiting successfully. /// /// This should only be modified by [overrideExitCode]. - int _exitCodeOverride; + int? _exitCodeOverride; /// Override the exit code that would normally be used when exiting /// successfully. Intended to be used by subcommands like `run` that wishes @@ -161,25 +175,40 @@ @nonVirtual FutureOr<int> run() async { computeCommand(_pubTopLevel.argResults); - if (_pubTopLevel.trace) { - log.recordTranscript(); - } + log.verbosity = _pubTopLevel.verbosity; log.fine('Pub ${sdk.version}'); + var crashed = false; try { - await captureErrors(runProtected, + await captureErrors<void>(() async => runProtected(), captureStackChains: _pubTopLevel.captureStackChains); if (_exitCodeOverride != null) { - return _exitCodeOverride; + return _exitCodeOverride!; } return exit_codes.SUCCESS; } catch (error, chain) { log.exception(error, chain); if (_pubTopLevel.trace) { - log.dumpTranscript(); + log.dumpTranscriptToStdErr(); } else if (!isUserFacingException(error)) { + log.error(''' +This is an unexpected error. The full log and other details are collected in: + + $transcriptPath + +Consider creating an issue on https://github.com/dart-lang/pub/issues/new +and attaching the relevant parts of that log file. +'''); + crashed = true; + } + return _chooseExitCode(error); + } finally { + final verbose = _pubTopLevel.verbosity == log.Verbosity.all; + + // Write the whole log transcript to file. + if (verbose || crashed) { // Escape the argument for users to copy-paste in bash. // Wrap with single quotation, and use '\'' to insert single quote, as // long as we have no spaces this doesn't create a new argument. @@ -187,29 +216,36 @@ RegExp(r'^[a-zA-Z0-9-_]+$').stringMatch(x) == null ? "'${x.replaceAll("'", r"'\''")}'" : x; - log.error(""" -This is an unexpected error. Please run - dart pub --trace ${_topCommand.name} ${_topCommand.argResults.arguments.map(protectArgument).join(' ')} + late final Entrypoint? e; + try { + e = entrypoint; + } on ApplicationException { + e = null; + } + log.dumpTranscriptToFile( + transcriptPath, + 'dart pub ${_topCommand.argResults!.arguments.map(protectArgument).join(' ')}', + e, + ); -and include the logs in an issue on https://github.com/dart-lang/pub/issues/new -"""); + if (!crashed) { + log.message('Logs written to $transcriptPath.'); + } } - return _chooseExitCode(error); - } finally { httpClient.close(); } } /// Returns the appropriate exit code for [exception], falling back on 1 if no /// appropriate exit code could be found. - int _chooseExitCode(exception) { + int _chooseExitCode(Object exception) { if (exception is SolveFailure) { var packageNotFound = exception.packageNotFound; if (packageNotFound != null) exception = packageNotFound; } while (exception is WrappedException && exception.innerError is Exception) { - exception = exception.innerError; + exception = exception.innerError!; } if (exception is HttpException || @@ -244,7 +280,7 @@ log.message(usage); } - static String _command; + static String? _command; /// Returns the nested name of the command that's currently being run. /// Examples: @@ -258,10 +294,10 @@ /// /// For top-level commands, if an alias is used, the primary command name is /// returned. For instance `install` becomes `get`. - static String get command => _command; + static late final String command = _command ?? ''; static void computeCommand(ArgResults argResults) { - var list = <String>[]; + var list = <String?>[]; for (var command = argResults.command; command != null; command = command.command) { @@ -269,9 +305,8 @@ if (list.isEmpty) { // this is a top-level command - final rootCommand = pubCommandAliases.entries.singleWhere( - (element) => element.value.contains(command.name), - orElse: () => null); + final rootCommand = pubCommandAliases.entries.singleWhereOrNull( + (element) => element.value.contains(command!.name)); if (rootCommand != null) { commandName = rootCommand.key; } @@ -280,13 +315,17 @@ } _command = list.join(' '); } + + String get transcriptPath { + return p.join(cache.rootDir, 'log', 'pub_log.txt'); + } } abstract class PubTopLevel { bool get captureStackChains; log.Verbosity get verbosity; bool get trace; - String get directory; + String? get directory; /// The argResults from the level of parsing of the 'pub' command. ArgResults get argResults;
diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart index 728f8ea..3557104 100644 --- a/lib/src/command/add.dart +++ b/lib/src/command/add.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:collection/collection.dart' show IterableExtension; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:yaml/yaml.dart'; @@ -14,6 +13,7 @@ import '../exceptions.dart'; import '../git.dart'; import '../io.dart'; +import '../language_version.dart'; import '../log.dart' as log; import '../package.dart'; import '../package_name.dart'; @@ -34,9 +34,10 @@ @override String get name => 'add'; @override - String get description => 'Add a dependency to pubspec.yaml.'; + String get description => 'Add dependencies to pubspec.yaml.'; @override - String get argumentsDescription => '<package>[:<constraint>] [options]'; + String get argumentsDescription => + '<package>[:<constraint>] [<package2>[:<constraint2>]...] [options]'; @override String get docUrl => 'https://dart.dev/tools/pub/cmd/pub-add'; @override @@ -44,29 +45,34 @@ bool get isDev => argResults['dev']; bool get isDryRun => argResults['dry-run']; - String get gitUrl => argResults['git-url']; - String get gitPath => argResults['git-path']; - String get gitRef => argResults['git-ref']; - String get hostUrl => argResults['hosted-url']; - String get path => argResults['path']; - String get sdk => argResults['sdk']; + String? get gitUrl => argResults['git-url']; + String? get gitPath => argResults['git-path']; + String? get gitRef => argResults['git-ref']; + String? get hostUrl => argResults['hosted-url']; + String? get path => argResults['path']; + String? get sdk => argResults['sdk']; bool get hasGitOptions => gitUrl != null || gitRef != null || gitPath != null; bool get hasHostOptions => hostUrl != null; + bool get isHosted => !hasGitOptions && path == null && path == null; + AddCommand() { argParser.addFlag('dev', abbr: 'd', negatable: false, - help: 'Adds package to the development dependencies instead.'); + help: 'Adds to the development dependencies instead.'); argParser.addOption('git-url', help: 'Git URL of the package'); argParser.addOption('git-ref', help: 'Git branch or commit to be retrieved'); argParser.addOption('git-path', help: 'Path of git package in repository'); argParser.addOption('hosted-url', help: 'URL of package host server'); - argParser.addOption('path', help: 'Local path'); - argParser.addOption('sdk', help: 'SDK source for package'); + argParser.addOption('path', help: 'Add package from local path'); + argParser.addOption('sdk', + help: 'add package from SDK source', + allowed: ['flutter'], + valueHelp: '[flutter]'); argParser.addFlag( 'example', help: @@ -85,25 +91,32 @@ argParser.addFlag('precompile', help: 'Build executables in immediate dependencies.'); argParser.addOption('directory', - abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir'); + abbr: 'C', help: 'Run this in the directory <dir>.', valueHelp: 'dir'); + argParser.addFlag('legacy-packages-file', + help: 'Generate the legacy ".packages" file', negatable: false); } @override Future<void> runProtected() async { if (argResults.rest.isEmpty) { - usageException('Must specify a package to be added.'); - } else if (argResults.rest.length > 1) { - usageException('Takes only a single argument.'); + usageException('Must specify at least one package to be added.'); + } else if (argResults.rest.length > 1 && gitUrl != null) { + usageException('Can only add a single git package at a time.'); + } else if (argResults.rest.length > 1 && path != null) { + usageException('Can only add a single local package at a time.'); + } + final languageVersion = entrypoint.root.pubspec.languageVersion; + final updates = + argResults.rest.map((p) => _parsePackage(p, languageVersion)).toList(); + + var updatedPubSpec = entrypoint.root.pubspec; + for (final update in updates) { + /// Perform version resolution in-memory. + updatedPubSpec = + await _addPackageToPubspec(updatedPubSpec, update.packageRange); } - final packageInformation = _parsePackage(argResults.rest.first); - final package = packageInformation.first; - - /// Perform version resolution in-memory. - final updatedPubSpec = - await _addPackageToPubspec(entrypoint.root.pubspec, package); - - SolveResult solveResult; + late SolveResult solveResult; try { /// Use [SolveType.UPGRADE] to solve for the highest version of [package] @@ -112,9 +125,11 @@ /// that a resolution exists before we update pubspec.yaml. // TODO(sigurdm): We should really use a spinner here. solveResult = await resolveVersions( - SolveType.UPGRADE, cache, Package.inMemory(updatedPubSpec)); + SolveType.upgrade, cache, Package.inMemory(updatedPubSpec)); } on GitException { - dataError('Unable to resolve package "${package.name}" with the given ' + final packageRange = updates.first.packageRange; + dataError( + 'Unable to resolve package "${packageRange.name}" with the given ' 'git parameters.'); } on SolveFailure catch (e) { dataError(e.message); @@ -123,56 +138,63 @@ dataError(e.message); } - final resultPackage = solveResult.packages - .firstWhere((packageId) => packageId.name == package.name); + /// Verify the results for each package. + for (final update in updates) { + final packageRange = update.packageRange; + final name = packageRange.name; + final resultPackage = solveResult.packages + .firstWhere((packageId) => packageId.name == name); - /// Assert that [resultPackage] is within the original user's expectations. - if (package.constraint != null && - !package.constraint.allows(resultPackage.version)) { - if (updatedPubSpec.dependencyOverrides != null && - updatedPubSpec.dependencyOverrides.isNotEmpty) { - dataError( - '"${package.name}" resolved to "${resultPackage.version}" which ' - 'does not satisfy constraint "${package.constraint}". This could be ' - 'caused by "dependency_overrides".'); + /// Assert that [resultPackage] is within the original user's expectations. + var constraint = packageRange.constraint; + if (!constraint.allows(resultPackage.version)) { + var dependencyOverrides = updatedPubSpec.dependencyOverrides; + if (dependencyOverrides.isNotEmpty) { + dataError('"$name" resolved to "${resultPackage.version}" which ' + 'does not satisfy constraint "$constraint". This could be ' + 'caused by "dependency_overrides".'); + } + dataError('"$name" resolved to "${resultPackage.version}" which ' + 'does not satisfy constraint "$constraint".'); } - dataError( - '"${package.name}" resolved to "${resultPackage.version}" which ' - 'does not satisfy constraint "${package.constraint}".'); } - if (isDryRun) { /// Even if it is a dry run, run `acquireDependencies` so that the user /// gets a report on the other packages that might change version due /// to this new dependency. final newRoot = Package.inMemory(updatedPubSpec); - // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output - await Entrypoint.global(newRoot, entrypoint.lockFile, cache, - solveResult: solveResult) - .acquireDependencies( - SolveType.GET, - dryRun: true, - precompile: argResults['precompile'], - ); + await Entrypoint.inMemory(newRoot, cache, + solveResult: solveResult, lockFile: entrypoint.lockFile) + .acquireDependencies(SolveType.get, + dryRun: true, + precompile: argResults['precompile'], + analytics: analytics, + generateDotPackages: false); } else { /// Update the `pubspec.yaml` before calling [acquireDependencies] to /// ensure that the modification timestamp on `pubspec.lock` and /// `.dart_tool/package_config.json` is newer than `pubspec.yaml`, /// ensuring that [entrypoint.assertUptoDate] will pass. - _updatePubspec(resultPackage, packageInformation, isDev); + _updatePubspec(solveResult.packages, updates, isDev); /// Create a new [Entrypoint] since we have to reprocess the updated /// pubspec file. final updatedEntrypoint = Entrypoint(directory, cache); - await updatedEntrypoint.acquireDependencies(SolveType.GET, - precompile: argResults['precompile']); + await updatedEntrypoint.acquireDependencies( + SolveType.get, + precompile: argResults['precompile'], + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], + ); if (argResults['example'] && entrypoint.example != null) { - await entrypoint.example.acquireDependencies( - SolveType.GET, + await entrypoint.example!.acquireDependencies( + SolveType.get, precompile: argResults['precompile'], onlyReportSuccessOrFailure: true, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], ); } } @@ -272,9 +294,7 @@ /// /// If any of the other git options are defined when `--git-url` is not /// defined, an error will be thrown. - Pair<PackageRange, dynamic> _parsePackage(String package) { - ArgumentError.checkNotNull(package, 'package'); - + _ParseResult _parsePackage(String package, LanguageVersion languageVersion) { final _conflictingFlagSets = [ ['git-url', 'git-ref', 'git-path'], ['hosted-url'], @@ -287,7 +307,7 @@ final conflictingFlag = _conflictingFlagSets .where((s) => !s.contains(flag)) .expand((s) => s) - .firstWhere(argResults.wasParsed, orElse: () => null); + .firstWhereOrNull(argResults.wasParsed); if (conflictingFlag != null) { usageException( 'Packages can only have one source, "pub add" flags "--$flag" and ' @@ -314,7 +334,7 @@ /// We want to allow for [constraint] to take on a `null` value here to /// preserve the fact that the user did not specify a constraint. - VersionConstraint constraint; + VersionConstraint? constraint; try { constraint = splitPackage.length == 2 @@ -326,6 +346,7 @@ /// Determine the relevant [packageRange] and [pubspecInformation] depending /// on the type of package. + var path = this.path; if (hasGitOptions) { dynamic git; @@ -334,7 +355,7 @@ } Uri parsed; try { - parsed = Uri.parse(gitUrl); + parsed = Uri.parse(gitUrl!); } on FormatException catch (e) { usageException('The --git-url must be a valid url: ${e.message}.'); } @@ -357,7 +378,7 @@ git.removeWhere((key, value) => value == null); } - packageRange = cache.sources['git'] + packageRange = cache.sources.git .parseRef(packageName, git, containingPath: entrypoint.pubspecPath) .withConstraint(constraint ?? VersionConstraint.any); pubspecInformation = {'git': git}; @@ -366,28 +387,38 @@ ? PathSource.relativePathWithPosixSeparators( p.relative(path, from: entrypoint.root.dir)) : path; - packageRange = cache.sources['path'] + packageRange = cache.sources.path .parseRef(packageName, relativeToEntryPoint, containingPath: entrypoint.pubspecPath) .withConstraint(constraint ?? VersionConstraint.any); pubspecInformation = {'path': relativeToEntryPoint}; } else if (sdk != null) { - packageRange = cache.sources['sdk'] + packageRange = cache.sources.sdk .parseRef(packageName, sdk) .withConstraint(constraint ?? VersionConstraint.any); pubspecInformation = {'sdk': sdk}; } else { - final hostInfo = - hasHostOptions ? {'url': hostUrl, 'name': packageName} : null; - - if (hostInfo == null) { - pubspecInformation = constraint?.toString(); + // Hosted + final Object? hostInfo; + if (hasHostOptions) { + hostInfo = languageVersion.supportsShorterHostedSyntax + ? hostUrl + : {'url': hostUrl, 'name': packageName}; + pubspecInformation = { + 'hosted': hostInfo, + }; } else { - pubspecInformation = {'hosted': hostInfo}; + hostInfo = null; + pubspecInformation = constraint?.toString(); } - packageRange = PackageRange(packageName, cache.sources['hosted'], - constraint ?? VersionConstraint.any, hostInfo ?? packageName); + packageRange = cache.hosted.source + .parseRef( + packageName, + hostInfo, + languageVersion: entrypoint.root.pubspec.languageVersion, + ) + .withConstraint(constraint ?? VersionConstraint.any); } if (pubspecInformation is Map && constraint != null) { @@ -400,65 +431,64 @@ }; } - return Pair(packageRange, pubspecInformation); + return _ParseResult(packageRange, pubspecInformation); } /// Writes the changes to the pubspec file. - void _updatePubspec(PackageId resultPackage, - Pair<PackageRange, dynamic> packageInformation, bool isDevelopment) { - ArgumentError.checkNotNull(resultPackage, 'resultPackage'); - ArgumentError.checkNotNull(packageInformation, 'pubspecInformation'); - - final package = packageInformation.first; - var pubspecInformation = packageInformation.last; - - if ((sdk != null || hasHostOptions) && - pubspecInformation is Map && - pubspecInformation['version'] == null) { - /// We cannot simply assign the value of version since it is likely that - /// [pubspecInformation] takes on the type - /// [Map<String, Map<String, String>>] - pubspecInformation = { - ...pubspecInformation, - 'version': '^${resultPackage.version}' - }; - } - - final dependencyKey = isDevelopment ? 'dev_dependencies' : 'dependencies'; - final packagePath = [dependencyKey, package.name]; - + void _updatePubspec(List<PackageId> resultPackages, + List<_ParseResult> updates, bool isDevelopment) { final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); log.io('Reading ${entrypoint.pubspecPath}.'); log.fine('Contents:\n$yamlEditor'); - /// Handle situations where the user might not have the dependencies or - /// dev_dependencies map. - if (yamlEditor.parseAt([dependencyKey], orElse: () => null)?.value == - null) { - yamlEditor.update([dependencyKey], - {package.name: pubspecInformation ?? '^${resultPackage.version}'}); - } else { - yamlEditor.update( - packagePath, pubspecInformation ?? '^${resultPackage.version}'); - } + for (final update in updates) { + final packageRange = update.packageRange; + final name = packageRange.name; + final resultId = resultPackages.firstWhere((id) => id.name == name); + var description = update.description; - log.fine('Added ${package.name} to "$dependencyKey".'); - - /// Remove the package from dev_dependencies if we are adding it to - /// dependencies. Refer to [_addPackageToPubspec] for additional discussion. - if (!isDevelopment) { - final devDependenciesNode = - yamlEditor.parseAt(['dev_dependencies'], orElse: () => null); - - if (devDependenciesNode is YamlMap && - devDependenciesNode.containsKey(package.name)) { - if (devDependenciesNode.length == 1) { - yamlEditor.remove(['dev_dependencies']); - } else { - yamlEditor.remove(['dev_dependencies', package.name]); + if (isHosted) { + final inferredConstraint = + VersionConstraint.compatibleWith(resultId.version).toString(); + if (description == null) { + description = inferredConstraint; + } else if (description is Map && description['version'] == null) { + /// We cannot simply assign the value of version since it is likely that + /// [description] takes on the type + /// [Map<String, Map<String, String>>] + description = {...description, 'version': '^${resultId.version}'}; } + } - log.fine('Removed ${package.name} from "dev_dependencies".'); + final dependencyKey = isDevelopment ? 'dev_dependencies' : 'dependencies'; + final packagePath = [dependencyKey, name]; + + /// Ensure we have a [dependencyKey] map in the `pubspec.yaml`. + if (yamlEditor.parseAt([dependencyKey], + orElse: () => YamlScalar.wrap(null)).value == + null) { + yamlEditor.update([dependencyKey], {}); + } + yamlEditor.update(packagePath, description); + + log.fine('Added ${packageRange.name} to "$dependencyKey".'); + + /// Remove the package from dev_dependencies if we are adding it to + /// dependencies. Refer to [_addPackageToPubspec] for additional discussion. + if (!isDevelopment) { + final devDependenciesNode = yamlEditor + .parseAt(['dev_dependencies'], orElse: () => YamlScalar.wrap(null)); + + if (devDependenciesNode is YamlMap && + devDependenciesNode.containsKey(name)) { + if (devDependenciesNode.length == 1) { + yamlEditor.remove(['dev_dependencies']); + } else { + yamlEditor.remove(['dev_dependencies', name]); + } + + log.fine('Removed $name from "dev_dependencies".'); + } } } @@ -466,3 +496,9 @@ writeTextFile(entrypoint.pubspecPath, yamlEditor.toString()); } } + +class _ParseResult { + PackageRange packageRange; + Object? description; + _ParseResult(this.packageRange, this.description); +}
diff --git a/lib/src/command/barback.dart b/lib/src/command/barback.dart index f059827..d058015 100644 --- a/lib/src/command/barback.dart +++ b/lib/src/command/barback.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import '../log.dart' as log; import '../utils.dart';
diff --git a/lib/src/command/build.dart b/lib/src/command/build.dart index 6673722..8c199d6 100644 --- a/lib/src/command/build.dart +++ b/lib/src/command/build.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'barback.dart'; /// Handles the `build` pub command.
diff --git a/lib/src/command/cache.dart b/lib/src/command/cache.dart index baa7403..12c4fbf 100644 --- a/lib/src/command/cache.dart +++ b/lib/src/command/cache.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import 'cache_add.dart'; import 'cache_clean.dart';
diff --git a/lib/src/command/cache_add.dart b/lib/src/command/cache_add.dart index 8dc76b7..e3e64e4 100644 --- a/lib/src/command/cache_add.dart +++ b/lib/src/command/cache_add.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart';
diff --git a/lib/src/command/cache_clean.dart b/lib/src/command/cache_clean.dart index e5ae0df..42b0f1f 100644 --- a/lib/src/command/cache_clean.dart +++ b/lib/src/command/cache_clean.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import '../command_runner.dart'; import '../io.dart';
diff --git a/lib/src/command/cache_list.dart b/lib/src/command/cache_list.dart index 9316172..f5ec62e 100644 --- a/lib/src/command/cache_list.dart +++ b/lib/src/command/cache_list.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import '../command.dart';
diff --git a/lib/src/command/cache_repair.dart b/lib/src/command/cache_repair.dart index 3658531..74968be 100644 --- a/lib/src/command/cache_repair.dart +++ b/lib/src/command/cache_repair.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../command.dart'; @@ -25,6 +23,8 @@ @override Future<void> runProtected() async { + // Delete any eventual temp-files left in the cache. + cache.deleteTempDir(); // Repair every cached source. final repairResults = (await Future.wait( cache.sources.all.map(cache.source).map((source) async {
diff --git a/lib/src/command/dependency_services.dart b/lib/src/command/dependency_services.dart index 9926731..8731fe3 100644 --- a/lib/src/command/dependency_services.dart +++ b/lib/src/command/dependency_services.dart
@@ -2,14 +2,13 @@ // 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. -// @dart=2.10 - /// This implements support for dependency-bot style automated upgrades. /// It is still work in progress - do not rely on the current output. import 'dart:convert'; import 'dart:io'; import 'package:async/async.dart' show collectBytes; +import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:yaml/yaml.dart'; import 'package:yaml_edit/yaml_edit.dart'; @@ -24,6 +23,7 @@ import '../pubspec_utils.dart'; import '../solver.dart'; import '../system_cache.dart'; +import '../utils.dart'; class DependencyServicesCommand extends PubCommand { @override @@ -64,16 +64,15 @@ final breakingPubspec = stripVersionUpperBounds(compatiblePubspec); - final compatiblePackagesResult = - await _tryResolve(compatiblePubspec, cache); + final compatiblePackagesResult = await _resolve(compatiblePubspec, cache); - final breakingPackagesResult = await _tryResolve(breakingPubspec, cache); + final breakingPackagesResult = await _resolve(breakingPubspec, cache); // This list will be empty if there is no lock file. final currentPackages = fileExists(entrypoint.lockFilePath) ? Map<String, PackageId>.from(entrypoint.lockFile.packages) : Map<String, PackageId>.fromIterable( - await _tryResolve(entrypoint.root.pubspec, cache), + await _resolve(entrypoint.root.pubspec, cache), key: (e) => e.name); currentPackages.remove(entrypoint.root.name); @@ -82,7 +81,7 @@ Future<List<Object>> _computeUpgradeSet( Pubspec rootPubspec, PackageId package, - {UpgradeType upgradeType}) async { + {required UpgradeType upgradeType}) async { final lockFile = entrypoint.lockFile; final pubspec = upgradeType == UpgradeType.multiBreaking ? stripVersionUpperBounds(rootPubspec) @@ -100,12 +99,14 @@ } final resolution = await tryResolveVersions( - SolveType.GET, + SolveType.get, cache, Package.inMemory(pubspec), lockFile: lockFile, ); + if (resolution == null) return []; + return [ ...resolution.packages.where((r) { if (r.name == rootPubspec.name) return false; @@ -132,12 +133,10 @@ } for (final package in currentPackages.values) { - final compatibleVersion = compatiblePackagesResult.firstWhere( - (element) => element.name == package.name, - orElse: () => null); - final multiBreakingVersion = breakingPackagesResult.firstWhere( - (element) => element.name == package.name, - orElse: () => null); + final compatibleVersion = compatiblePackagesResult + .firstWhereOrNull((element) => element.name == package.name); + final multiBreakingVersion = breakingPackagesResult + .firstWhereOrNull((element) => element.name == package.name); final singleBreakingPubspec = Pubspec( compatiblePubspec.name, version: compatiblePubspec.version, @@ -149,24 +148,24 @@ .toRange() .withConstraint(stripUpperBound(package.toRange().constraint)); final singleBreakingPackagesResult = - await _tryResolve(singleBreakingPubspec, cache); - final singleBreakingVersion = singleBreakingPackagesResult.firstWhere( - (element) => element.name == package.name, - orElse: () => null); + await _resolve(singleBreakingPubspec, cache); + final singleBreakingVersion = singleBreakingPackagesResult + .firstWhereOrNull((element) => element.name == package.name); dependencies.add({ 'name': package.name, 'version': package.version.toString(), 'kind': _kindString(compatiblePubspec, package.name), - 'latest': (await cache.getLatest(package)).version.toString(), + 'latest': (await cache.getLatest(package))?.version.toString(), 'constraint': _constraintOf(compatiblePubspec, package.name).toString(), if (compatibleVersion != null) 'compatible': await _computeUpgradeSet( compatiblePubspec, compatibleVersion, upgradeType: UpgradeType.compatible), - 'single-breaking': await _computeUpgradeSet( - singleBreakingPubspec, singleBreakingVersion, - upgradeType: UpgradeType.singleBreaking), + if (singleBreakingVersion != null) + 'single-breaking': await _computeUpgradeSet( + singleBreakingPubspec, singleBreakingVersion, + upgradeType: UpgradeType.singleBreaking), if (multiBreakingVersion != null) 'multi-breaking': await _computeUpgradeSet( breakingPubspec, multiBreakingVersion, @@ -177,11 +176,9 @@ } } -VersionConstraint _constraintOf(Pubspec pubspec, String packageName) { - return (pubspec.dependencies[packageName] ?? - pubspec.devDependencies[packageName]) - ?.constraint; -} +VersionConstraint? _constraintOf(Pubspec pubspec, String packageName) => + (pubspec.dependencies[packageName] ?? pubspec.devDependencies[packageName]) + ?.constraint; String _kindString(Pubspec pubspec, String packageName) { return pubspec.dependencies.containsKey(packageName) @@ -193,15 +190,13 @@ /// Try to solve [pubspec] return [PackageId]s in the resolution or `null` if no /// resolution was found. -Future<List<PackageId>> _tryResolve(Pubspec pubspec, SystemCache cache) async { - final solveResult = await tryResolveVersions( - SolveType.UPGRADE, - cache, - Package.inMemory(pubspec), - ); - - return solveResult?.packages; -} +Future<List<PackageId>> _resolve(Pubspec pubspec, SystemCache cache) async => + (await resolveVersions( + SolveType.upgrade, + cache, + Package.inMemory(pubspec), + )) + .packages; class DependencyServicesListCommand extends PubCommand { @override @@ -227,7 +222,7 @@ final currentPackages = fileExists(entrypoint.lockFilePath) ? Map<String, PackageId>.from(entrypoint.lockFile.packages) : Map<String, PackageId>.fromIterable( - await _tryResolve(entrypoint.root.pubspec, cache), + await _resolve(entrypoint.root.pubspec, cache), key: (e) => e.name); currentPackages.remove(entrypoint.root.name); @@ -273,11 +268,25 @@ YamlEditor(readTextFile(entrypoint.pubspecPath)); final toApply = <_PackageVersion>[]; final input = json.decode(utf8.decode(await collectBytes(stdin))); - for (final change in input['dependencyChanges']) { - toApply.add(_PackageVersion( - change['name'], - change['version'] != null ? Version.parse(change['version']) : null, - )); + final changes = input['dependencyChanges']; + if (changes is! List) { + dataError('The dependencyChanges field must be a list'); + } + for (final change in changes) { + final name = change['name']; + if (name is! String) { + dataError('The "name" field must be a string'); + } + final version = change['version']; + if (version is! String?) { + dataError('The "version" field must be a string'); + } + toApply.add( + _PackageVersion( + name, + version != null ? Version.parse(version) : null, + ), + ); } final pubspec = entrypoint.root.pubspec; @@ -301,7 +310,7 @@ VersionConstraint.compatibleWith(targetVersion).toString()); } - if (lockFile != null) { + if (lockFileEditor != null) { if (lockFileYaml['packages'].containsKey(targetPackage)) { lockFileEditor.update(['packages', targetPackage, 'version'], targetVersion.toString()); @@ -312,14 +321,18 @@ if (pubspecEditor.edits.isNotEmpty) { writeTextFile(entrypoint.pubspecPath, pubspecEditor.toString()); } - if (lockFile != null && lockFileEditor.edits.isNotEmpty) { + if (lockFileEditor != null && lockFileEditor.edits.isNotEmpty) { writeTextFile(entrypoint.lockFilePath, lockFileEditor.toString()); } await log.warningsOnlyUnlessTerminal( () => () async { // This will fail if the new configuration does not resolve. - await Entrypoint(directory, cache) - .acquireDependencies(SolveType.GET, dryRun: true); + await Entrypoint(directory, cache).acquireDependencies( + SolveType.get, + dryRun: true, + analytics: null, + generateDotPackages: false, + ); }, ); // Dummy message. @@ -329,6 +342,6 @@ class _PackageVersion { String name; - Version version; + Version? version; _PackageVersion(this.name, this.version); }
diff --git a/lib/src/command/deps.dart b/lib/src/command/deps.dart index 1742701..79463fc 100644 --- a/lib/src/command/deps.dart +++ b/lib/src/command/deps.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:collection'; import 'dart:convert'; @@ -37,7 +35,8 @@ AnalysisContextManager(); /// The [StringBuffer] used to accumulate the output. - StringBuffer _buffer; + // TODO(sigurdm): use a local variable for this. + final _buffer = StringBuffer(); /// Whether to include dev dependencies. bool get _includeDev => argResults['dev']; @@ -67,8 +66,7 @@ Future<void> runProtected() async { // Explicitly Run this in the directorycase we don't access `entrypoint.packageGraph`. entrypoint.assertUpToDate(); - - _buffer = StringBuffer(); + _buffer.clear(); if (argResults['json']) { if (argResults.wasParsed('dev')) { @@ -89,7 +87,7 @@ final current = toVisit.removeLast(); if (visited.contains(current)) continue; visited.add(current); - final currentPackage = entrypoint.packageGraph.packages[current]; + final currentPackage = entrypoint.packageGraph.packages[current]!; final next = (current == entrypoint.root.name ? entrypoint.root.immediateDependencies : currentPackage.dependencies) @@ -121,7 +119,7 @@ ...entrypoint.root.immediateDependencies.keys .map((name) => entrypoint.packageGraph.packages[name]) ]) - ...package.executableNames.map((name) => package == entrypoint.root + ...package!.executableNames.map((name) => package == entrypoint.root ? ':$name' : (package.name == name ? name : '${package.name}:$name')) ]; @@ -331,7 +329,6 @@ if (package != null) return package; dataError('The pubspec.yaml file has changed since the pubspec.lock file ' 'was generated, please run "$topLevelProgram pub get" again.'); - return null; } /// Outputs all executables reachable from [entrypoint]. @@ -342,7 +339,7 @@ ? entrypoint.root.immediateDependencies : entrypoint.root.dependencies) .keys - .map((name) => entrypoint.packageGraph.packages[name]) + .map((name) => entrypoint.packageGraph.packages[name]!) ]; for (var package in packages) {
diff --git a/lib/src/command/downgrade.dart b/lib/src/command/downgrade.dart index 2d0840a..fce5ef3 100644 --- a/lib/src/command/downgrade.dart +++ b/lib/src/command/downgrade.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../command.dart'; @@ -44,6 +42,8 @@ argParser.addOption('directory', abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir'); + argParser.addFlag('legacy-packages-file', + help: 'Generate the legacy ".packages" file', negatable: false); } @override @@ -53,16 +53,24 @@ 'The --packages-dir flag is no longer used and does nothing.')); } var dryRun = argResults['dry-run']; + await entrypoint.acquireDependencies( - SolveType.DOWNGRADE, + SolveType.downgrade, unlock: argResults.rest, dryRun: dryRun, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], ); - if (argResults['example'] && entrypoint.example != null) { - await entrypoint.example.acquireDependencies(SolveType.GET, - unlock: argResults.rest, - dryRun: dryRun, - onlyReportSuccessOrFailure: true); + var example = entrypoint.example; + if (argResults['example'] && example != null) { + await example.acquireDependencies( + SolveType.get, + unlock: argResults.rest, + dryRun: dryRun, + onlyReportSuccessOrFailure: true, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], + ); } if (isOffline) {
diff --git a/lib/src/command/get.dart b/lib/src/command/get.dart index 2709238..7b8906c 100644 --- a/lib/src/command/get.dart +++ b/lib/src/command/get.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../command.dart'; @@ -35,6 +33,9 @@ argParser.addFlag('packages-dir', hide: true); + argParser.addFlag('legacy-packages-file', + help: 'Generate the legacy ".packages" file', negatable: false); + argParser.addFlag( 'example', help: 'Also run in `example/` (if it exists).', @@ -51,14 +52,24 @@ log.warning(log.yellow( 'The --packages-dir flag is no longer used and does nothing.')); } - await entrypoint.acquireDependencies(SolveType.GET, - dryRun: argResults['dry-run'], precompile: argResults['precompile']); + await entrypoint.acquireDependencies( + SolveType.get, + dryRun: argResults['dry-run'], + precompile: argResults['precompile'], + generateDotPackages: argResults['legacy-packages-file'], + analytics: analytics, + ); - if (argResults['example'] && entrypoint.example != null) { - await entrypoint.example.acquireDependencies(SolveType.GET, - dryRun: argResults['dry-run'], - precompile: argResults['precompile'], - onlyReportSuccessOrFailure: true); + var example = entrypoint.example; + if (argResults['example'] && example != null) { + await example.acquireDependencies( + SolveType.get, + dryRun: argResults['dry-run'], + precompile: argResults['precompile'], + generateDotPackages: argResults['legacy-packages-file'], + analytics: analytics, + onlyReportSuccessOrFailure: true, + ); } } }
diff --git a/lib/src/command/global.dart b/lib/src/command/global.dart index b7f7b01..a7e8898 100644 --- a/lib/src/command/global.dart +++ b/lib/src/command/global.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import 'global_activate.dart'; import 'global_deactivate.dart';
diff --git a/lib/src/command/global_activate.dart b/lib/src/command/global_activate.dart index 2959e6e..a21386a 100644 --- a/lib/src/command/global_activate.dart +++ b/lib/src/command/global_activate.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; @@ -54,13 +52,13 @@ @override Future<void> runProtected() async { // Default to `null`, which means all executables. - List<String> executables; + List<String>? executables; if (argResults.wasParsed('executable')) { if (argResults.wasParsed('no-executables')) { usageException('Cannot pass both --no-executables and --executable.'); } - executables = argResults['executable'] as List<String>; + executables = argResults['executable']; } else if (argResults['no-executables']) { // An empty list means no executables. executables = []; @@ -78,8 +76,8 @@ features[feature] = FeatureDependency.unused; } - var overwrite = argResults['overwrite']; - Uri hostedUrl; + final overwrite = argResults['overwrite'] as bool; + Uri? hostedUrl; if (argResults.wasParsed('hosted-url')) { try { hostedUrl = validateAndNormalizeHostedUrl(argResults['hosted-url']); @@ -90,7 +88,7 @@ Iterable<String> args = argResults.rest; - dynamic readArg([String error]) { + String readArg([String error = '']) { if (args.isEmpty) usageException(error); var arg = args.first; args = args.skip(1); @@ -139,8 +137,12 @@ var path = readArg('No package to activate given.'); validateNoExtraArgs(); - return globals.activatePath(path, executables, - overwriteBinStubs: overwrite); + return globals.activatePath( + path, + executables, + overwriteBinStubs: overwrite, + analytics: analytics, + ); } throw StateError('unreachable');
diff --git a/lib/src/command/global_deactivate.dart b/lib/src/command/global_deactivate.dart index e06bb5e..7e99e19 100644 --- a/lib/src/command/global_deactivate.dart +++ b/lib/src/command/global_deactivate.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import '../log.dart' as log; import '../utils.dart';
diff --git a/lib/src/command/global_list.dart b/lib/src/command/global_list.dart index cd72791..5e22042 100644 --- a/lib/src/command/global_list.dart +++ b/lib/src/command/global_list.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; /// Handles the `global list` pub command.
diff --git a/lib/src/command/global_run.dart b/lib/src/command/global_run.dart index 28d5ca6..71e0a9d 100644 --- a/lib/src/command/global_run.dart +++ b/lib/src/command/global_run.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p; @@ -19,8 +17,7 @@ String get name => 'run'; @override String get description => - 'Run an executable from a globally activated package.\n' - "NOTE: We are currently optimizing this command's startup time."; + 'Run an executable from a globally activated package.'; @override String get argumentsDescription => '<package>:<executable> [args...]'; @override
diff --git a/lib/src/command/lish.dart b/lib/src/command/lish.dart index 151ee79..c927e07 100644 --- a/lib/src/command/lish.dart +++ b/lib/src/command/lish.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; @@ -36,15 +34,13 @@ bool get takesArguments => false; /// The URL of the server to which to upload the package. - Uri get server { - if (_server != null) { - return _server; - } + late final Uri server = _createServer(); + Uri _createServer() { // An explicit argument takes precedence. if (argResults.wasParsed('server')) { try { - return _server = validateAndNormalizeHostedUrl(argResults['server']); + return validateAndNormalizeHostedUrl(argResults['server']); } on FormatException catch (e) { usageException('Invalid server: $e'); } @@ -54,19 +50,16 @@ final publishTo = entrypoint.root.pubspec.publishTo; if (publishTo != null) { try { - return _server = validateAndNormalizeHostedUrl(publishTo); + return validateAndNormalizeHostedUrl(publishTo); } on FormatException catch (e) { throw DataException('Invalid publish_to: $e'); } } // Use the default server if nothing else is specified - return _server = cache.sources.hosted.defaultUrl; + return cache.sources.hosted.defaultUrl; } - /// Cache value for [server]. - Uri _server; - /// Whether the publish is just a preview. bool get dryRun => argResults['dry-run']; @@ -92,13 +85,13 @@ Future<void> _publishUsingClient( List<int> packageBytes, - http.BaseClient client, + http.Client client, ) async { - Uri cloudStorageUrl; + Uri? cloudStorageUrl; try { await log.progress('Uploading', () async { - var newUri = server.resolve('/api/packages/versions/new'); + var newUri = server.resolve('api/packages/versions/new'); var response = await client.get(newUri, headers: pubApiHeaders); var parameters = parseJsonResponse(response); @@ -107,7 +100,7 @@ cloudStorageUrl = Uri.parse(url); // TODO(nweiz): Cloud Storage can provide an XML-formatted error. We // should report that error and exit. - var request = http.MultipartRequest('POST', cloudStorageUrl); + var request = http.MultipartRequest('POST', cloudStorageUrl!); var fields = _expectField(parameters, 'fields', response); if (fields is! Map) invalidServerResponse(response); @@ -127,8 +120,24 @@ handleJsonSuccess( await client.get(Uri.parse(location), headers: pubApiHeaders)); }); + } on AuthenticationException catch (error) { + var msg = ''; + if (error.statusCode == 401) { + msg += '$server package repository requested authentication!\n' + 'You can provide credentials using:\n' + ' pub token add $server\n'; + } + if (error.statusCode == 403) { + msg += 'Insufficient permissions to the resource at the $server ' + 'package repository.\nYou can modify credentials using:\n' + ' pub token add $server\n'; + } + if (error.serverMessage != null) { + msg += '\n' + error.serverMessage! + '\n'; + } + dataError(msg + log.red('Authentication failed!')); } on PubHttpException catch (error) { - var url = error.response.request.url; + var url = error.response.request!.url; if (url == cloudStorageUrl) { // TODO(nweiz): the response may have XML-formatted information about // the error. Try to parse that out once we have an easily-accessible @@ -156,7 +165,8 @@ // explicitly have to define mock servers as official server to test // publish command with oauth2 credentials. if (runningFromTest && - Platform.environment.containsKey('PUB_HOSTED_URL')) + Platform.environment.containsKey('PUB_HOSTED_URL') && + Platform.environment['_PUB_TEST_AUTH_METHOD'] == 'oauth2') Platform.environment['PUB_HOSTED_URL'], }; @@ -172,7 +182,7 @@ }); } } on PubHttpException catch (error) { - var url = error.response.request.url; + var url = error.response.request!.url; if (Uri.parse(url.origin) == Uri.parse(server.origin)) { handleJsonError(error.response); } else {
diff --git a/lib/src/command/list_package_dirs.dart b/lib/src/command/list_package_dirs.dart index 96c0735..09d248e 100644 --- a/lib/src/command/list_package_dirs.dart +++ b/lib/src/command/list_package_dirs.dart
@@ -2,15 +2,13 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import '../command.dart'; import '../command_runner.dart'; -import '../exit_codes.dart' as exit_codes; import '../io.dart'; import '../log.dart' as log; +import '../package_name.dart'; import '../utils.dart'; /// Handles the `list-package-dirs` pub command. @@ -45,7 +43,8 @@ var output = {}; // Include the local paths to all locked packages. - var packages = mapMap(entrypoint.lockFile.packages, value: (name, package) { + var packages = mapMap(entrypoint.lockFile.packages, + value: (String name, PackageId package) { var source = entrypoint.cache.source(package.source); var packageDir = source.getDirectory(package); // Normalize paths and make them absolute for backwards compatibility @@ -67,6 +66,5 @@ ]; log.json.message(output); - return exit_codes.SUCCESS; } }
diff --git a/lib/src/command/login.dart b/lib/src/command/login.dart index 747bb55..8c31e69 100644 --- a/lib/src/command/login.dart +++ b/lib/src/command/login.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -40,7 +38,7 @@ } } - Future<_UserInfo> _retrieveUserInfo() async { + Future<_UserInfo?> _retrieveUserInfo() async { return await oauth2.withClient(cache, (client) async { final discovery = await httpClient.get(Uri.https( 'accounts.google.com', '/.well-known/openid-configuration')); @@ -62,5 +60,5 @@ final String email; _UserInfo(this.name, this.email); @override - String toString() => ['<$email>', if (name != null) name].join(' '); + String toString() => ['<$email>', name].join(' '); }
diff --git a/lib/src/command/logout.dart b/lib/src/command/logout.dart index 071e8c0..04ffe12 100644 --- a/lib/src/command/logout.dart +++ b/lib/src/command/logout.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../command.dart';
diff --git a/lib/src/command/outdated.dart b/lib/src/command/outdated.dart index 444bd03..2941952 100644 --- a/lib/src/command/outdated.dart +++ b/lib/src/command/outdated.dart
@@ -2,14 +2,13 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'package:meta/meta.dart'; +import 'package:collection/collection.dart' + show IterableExtension, IterableNullableExtension; import 'package:path/path.dart' as path; import '../command.dart'; @@ -119,7 +118,7 @@ 'outdated': _OutdatedMode(), 'null-safety': _NullSafetyMode(cache, entrypoint, shouldShowSpinner: _shouldShowSpinner), - }[argResults['mode']]; + }[argResults['mode']]!; final includeDevDependencies = argResults['dev-dependencies']; final includeDependencyOverrides = argResults['dependency-overrides']; @@ -138,10 +137,10 @@ final resolvablePubspec = await mode.resolvablePubspec(upgradablePubspec); - List<PackageId> upgradablePackages; - List<PackageId> resolvablePackages; - bool hasUpgradableResolution; - bool hasResolvableResolution; + late List<PackageId> upgradablePackages; + late List<PackageId> resolvablePackages; + late bool hasUpgradableResolution; + late bool hasResolvableResolution; await log.spinner('Resolving', () async { final upgradablePackagesResult = @@ -169,16 +168,16 @@ Future<_PackageDetails> analyzeDependency(PackageRef packageRef) async { final name = packageRef.name; - final current = (entrypoint.lockFile?.packages ?? {})[name]; + final current = entrypoint.lockFile.packages[name]; - final upgradable = upgradablePackages.firstWhere((id) => id.name == name, - orElse: () => null); - final resolvable = resolvablePackages.firstWhere((id) => id.name == name, - orElse: () => null); + final upgradable = + upgradablePackages.firstWhereOrNull((id) => id.name == name); + final resolvable = + resolvablePackages.firstWhereOrNull((id) => id.name == name); // Find the latest version, and if it's overridden. var latestIsOverridden = false; - PackageId latest; + PackageId? latest; // If not overridden in current resolution we can use this if (!entrypoint.root.pubspec.dependencyOverrides.containsKey(name)) { latest ??= @@ -296,27 +295,25 @@ return argResults['mode'] != 'null-safety'; } - bool _prereleases; - - bool get prereleases => _prereleases ??= () { - // First check if 'prereleases' was passed as an argument. - // If that was not the case, check for use of the legacy spelling - // 'pre-releases'. - // Otherwise fall back to the default implied by the mode. - if (argResults.wasParsed('prereleases')) { - return argResults['prereleases']; - } - if (argResults.wasParsed('pre-releases')) { - return argResults['pre-releases']; - } - return argResults['mode'] == 'null-safety'; - }(); + late final bool prereleases = () { + // First check if 'prereleases' was passed as an argument. + // If that was not the case, check for use of the legacy spelling + // 'pre-releases'. + // Otherwise fall back to the default implied by the mode. + if (argResults.wasParsed('prereleases')) { + return argResults['prereleases']; + } + if (argResults.wasParsed('pre-releases')) { + return argResults['pre-releases']; + } + return argResults['mode'] == 'null-safety'; + }(); /// Retrieves the pubspec of package [name] in [version] from [source]. /// /// Returns `null`, if given `null` as a convinience. - Future<_VersionDetails> _describeVersion( - PackageId id, + Future<_VersionDetails?> _describeVersion( + PackageId? id, bool isOverridden, ) async { if (id == null) { @@ -367,9 +364,9 @@ /// Try to solve [pubspec] return [PackageId]s in the resolution or `null` if no /// resolution was found. -Future<List<PackageId>> _tryResolve(Pubspec pubspec, SystemCache cache) async { +Future<List<PackageId>?> _tryResolve(Pubspec pubspec, SystemCache cache) async { final solveResult = await tryResolveVersions( - SolveType.UPGRADE, + SolveType.upgrade, cache, Package.inMemory(pubspec), ); @@ -380,13 +377,13 @@ Future<void> _outputJson( List<_PackageDetails> rows, Mode mode, { - @required bool showAll, - @required bool includeDevDependencies, + required bool showAll, + required bool includeDevDependencies, }) async { final markedRows = Map.fromIterables(rows, await mode.markVersionDetails(rows)); if (!showAll) { - rows.removeWhere((row) => markedRows[row][0].asDesired); + rows.removeWhere((row) => markedRows[row]![0].asDesired); } if (!includeDevDependencies) { rows.removeWhere( @@ -402,10 +399,10 @@ ...(rows..sort((a, b) => a.name.compareTo(b.name))) .map((packageDetails) => { 'package': packageDetails.name, - 'current': markedRows[packageDetails][0]?.toJson(), - 'upgradable': markedRows[packageDetails][1]?.toJson(), - 'resolvable': markedRows[packageDetails][2]?.toJson(), - 'latest': markedRows[packageDetails][3]?.toJson(), + 'current': markedRows[packageDetails]![0].toJson(), + 'upgradable': markedRows[packageDetails]![1].toJson(), + 'resolvable': markedRows[packageDetails]![2].toJson(), + 'latest': markedRows[packageDetails]![3].toJson(), }) ] }, @@ -416,16 +413,16 @@ Future<void> _outputHuman( List<_PackageDetails> rows, Mode mode, { - @required bool showAll, - @required bool useColors, - @required bool includeDevDependencies, - @required bool lockFileExists, - @required bool hasDirectDependencies, - @required bool hasDevDependencies, - @required bool showTransitiveDependencies, - @required bool hasUpgradableResolution, - @required bool hasResolvableResolution, - @required String directory, + required bool showAll, + required bool useColors, + required bool includeDevDependencies, + required bool lockFileExists, + required bool hasDirectDependencies, + required bool hasDevDependencies, + required bool showTransitiveDependencies, + required bool hasUpgradableResolution, + required bool hasResolvableResolution, + required String directory, }) async { final directoryDesc = directory == '.' ? '' : ' in $directory'; log.message(mode.explanation(directoryDesc) + '\n'); @@ -434,11 +431,11 @@ List<_FormattedString> formatted(_PackageDetails package) => [ _FormattedString(package.name), - ...markedRows[package].map((m) => m.toHuman()), + ...markedRows[package]!.map((m) => m.toHuman()), ]; if (!showAll) { - rows.removeWhere((row) => markedRows[row][0].asDesired); + rows.removeWhere((row) => markedRows[row]![0].asDesired); } if (rows.isEmpty) { log.message(mode.foundNoBadText); @@ -506,7 +503,8 @@ for (var j = 0; j < row.length; j++) { b.write(row[j].formatted(useColors: useColors)); b.write(' ' * - ((columnWidths[j] + 2) - row[j].computeLength(useColors: useColors))); + ((columnWidths[j]! + 2) - + row[j].computeLength(useColors: useColors))); } log.message(b.toString()); } @@ -624,15 +622,15 @@ final rows = <List<_MarkedVersionDetails>>[]; for (final packageDetails in packages) { final cols = <_MarkedVersionDetails>[]; - _VersionDetails previous; + _VersionDetails? previous; for (final versionDetails in [ packageDetails.current, packageDetails.upgradable, packageDetails.resolvable, packageDetails.latest ]) { - String Function(String) color; - String prefix; + String Function(String)? color; + String? prefix; var asDesired = false; if (versionDetails != null) { final isLatest = versionDetails == packageDetails.latest; @@ -660,8 +658,8 @@ } @override - Future<Pubspec> resolvablePubspec(Pubspec pubspec) async { - return stripVersionUpperBounds(pubspec); + Future<Pubspec> resolvablePubspec(Pubspec? pubspec) async { + return stripVersionUpperBounds(pubspec!); } } @@ -674,7 +672,7 @@ final _notCompliantEmoji = emoji('✗', 'x'); _NullSafetyMode(this.cache, this.entrypoint, - {@required this.shouldShowSpinner}); + {required this.shouldShowSpinner}); @override String explanation(String directoryDescription) => ''' @@ -714,14 +712,14 @@ packageDetails.resolvable?._id, packageDetails.latest?._id, ] - }.where((id) => id != null); + }.whereNotNull(); return Map.fromEntries( await Future.wait( ids.map( (id) async => MapEntry( id, - (await id.source.bind(cache).describe(id)) + (await id.source!.bind(cache).describe(id)) .languageVersion .supportsNullSafety), ), @@ -737,20 +735,20 @@ packageDetails.latest ].map( (versionDetails) { - String Function(String) color; - String prefix; - bool nullSafetyJson; + String Function(String)? color; + String? prefix; + MapEntry<String, Object>? jsonExplanation; var asDesired = false; if (versionDetails != null) { - if (nullSafetyMap[versionDetails._id]) { + if (nullSafetyMap[versionDetails._id]!) { color = log.green; prefix = _compliantEmoji; - nullSafetyJson = true; + jsonExplanation = MapEntry('nullSafety', true); asDesired = true; } else { color = log.red; prefix = _notCompliantEmoji; - nullSafetyJson = false; + jsonExplanation = MapEntry('nullSafety', false); } } return _MarkedVersionDetails( @@ -758,7 +756,7 @@ asDesired: asDesired, format: color, prefix: prefix, - jsonExplanation: MapEntry('nullSafety', nullSafetyJson), + jsonExplanation: jsonExplanation, ); }, ).toList() @@ -809,14 +807,17 @@ _overridden == other._overridden && _id.source == other._id.source && _pubspec.version == other._pubspec.version; + + @override + int get hashCode => Object.hash(_pubspec.version, _id.source, _overridden); } class _PackageDetails implements Comparable<_PackageDetails> { final String name; - final _VersionDetails current; - final _VersionDetails upgradable; - final _VersionDetails resolvable; - final _VersionDetails latest; + final _VersionDetails? current; + final _VersionDetails? upgradable; + final _VersionDetails? resolvable; + final _VersionDetails? latest; final _DependencyKind kind; _PackageDetails(this.name, this.current, this.upgradable, this.resolvable, @@ -830,7 +831,7 @@ return name.compareTo(other.name); } - Map<String, Object> toJson() { + Map<String, Object?> toJson() { return { 'package': name, 'current': current?.toJson(), @@ -870,15 +871,16 @@ devTransitive, } -_FormattedString _format(String value, Function(String) format, {prefix = ''}) { +_FormattedString _format(String value, String Function(String) format, + {prefix = ''}) { return _FormattedString(value, format: format, prefix: prefix); } class _MarkedVersionDetails { - final MapEntry<String, Object> _jsonExplanation; - final _VersionDetails _versionDetails; - final String Function(String) _format; - final String _prefix; + final MapEntry<String, Object>? _jsonExplanation; + final _VersionDetails? _versionDetails; + final String Function(String)? _format; + final String? _prefix; /// This should be true if the mode creating this consideres the version as /// "good". @@ -889,7 +891,7 @@ _MarkedVersionDetails( this._versionDetails, { - @required this.asDesired, + required this.asDesired, format, prefix = '', jsonExplanation, @@ -903,12 +905,13 @@ prefix: _prefix, ); - Object toJson() { + Object? toJson() { if (_versionDetails == null) return null; - return _jsonExplanation == null - ? _versionDetails.toJson() - : (_versionDetails.toJson()..addEntries([_jsonExplanation])); + var jsonExplanation = _jsonExplanation; + return jsonExplanation == null + ? _versionDetails!.toJson() + : (_versionDetails!.toJson()..addEntries([jsonExplanation])); } } @@ -921,15 +924,15 @@ /// A prefix for marking this string if colors are not used. final String _prefix; - _FormattedString(this.value, {String Function(String) format, prefix}) + _FormattedString(this.value, {String Function(String)? format, prefix}) : _format = format ?? _noFormat, _prefix = prefix ?? ''; - String formatted({@required bool useColors}) { + String formatted({required bool useColors}) { return useColors ? _format(_prefix + value) : _prefix + value; } - int computeLength({@required bool useColors}) { + int computeLength({required bool? useColors}) { return _prefix.length + value.length; }
diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart index f505785..82a9547 100644 --- a/lib/src/command/remove.dart +++ b/lib/src/command/remove.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:yaml/yaml.dart'; import 'package:yaml_edit/yaml_edit.dart'; @@ -52,6 +50,9 @@ argParser.addOption('directory', abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir'); + + argParser.addFlag('legacy-packages-file', + help: 'Generate the legacy ".packages" file', negatable: false); } @override @@ -67,12 +68,12 @@ final newPubspec = _removePackagesFromPubspec(rootPubspec, packages); final newRoot = Package.inMemory(newPubspec); - await Entrypoint.global(newRoot, entrypoint.lockFile, cache) - .acquireDependencies( - SolveType.GET, - precompile: argResults['precompile'], - dryRun: true, - ); + await Entrypoint.inMemory(newRoot, cache, lockFile: entrypoint.lockFile) + .acquireDependencies(SolveType.get, + precompile: argResults['precompile'], + dryRun: true, + analytics: null, + generateDotPackages: false); } else { /// Update the pubspec. _writeRemovalToPubspec(packages); @@ -80,13 +81,22 @@ /// Create a new [Entrypoint] since we have to reprocess the updated /// pubspec file. final updatedEntrypoint = Entrypoint(directory, cache); - await updatedEntrypoint.acquireDependencies(SolveType.GET, - precompile: argResults['precompile']); + await updatedEntrypoint.acquireDependencies( + SolveType.get, + precompile: argResults['precompile'], + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], + ); - if (argResults['example'] && entrypoint.example != null) { - await entrypoint.example.acquireDependencies(SolveType.GET, - precompile: argResults['precompile'], - onlyReportSuccessOrFailure: true); + var example = entrypoint.example; + if (argResults['example'] && example != null) { + await example.acquireDependencies( + SolveType.get, + precompile: argResults['precompile'], + onlyReportSuccessOrFailure: true, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], + ); } } } @@ -122,8 +132,8 @@ /// There may be packages where the dependency is declared both in /// dependencies and dev_dependencies. for (final dependencyKey in ['dependencies', 'dev_dependencies']) { - final dependenciesNode = - yamlEditor.parseAt([dependencyKey], orElse: () => null); + final dependenciesNode = yamlEditor + .parseAt([dependencyKey], orElse: () => YamlScalar.wrap(null)); if (dependenciesNode is YamlMap && dependenciesNode.containsKey(package)) {
diff --git a/lib/src/command/run.dart b/lib/src/command/run.dart index c706c72..e223c5a 100644 --- a/lib/src/command/run.dart +++ b/lib/src/command/run.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p; @@ -45,8 +43,6 @@ argParser.addFlag('sound-null-safety', help: 'Override the default null safety execution mode.'); argParser.addOption('mode', help: 'Deprecated option', hide: true); - // mode exposed for `dartdev run` to use as subprocess. - argParser.addFlag('dart-dev-run', hide: true); argParser.addOption('directory', abbr: 'C', help: 'Run this in the directory<dir>.', valueHelp: 'dir'); } @@ -58,9 +54,6 @@ log.message('Deprecated. Use `dart run` instead.'); }); } - if (argResults['dart-dev-run']) { - return await _runFromDartDev(); - } if (argResults.rest.isEmpty) { usageException('Must specify an executable to run.'); } @@ -104,54 +97,4 @@ ); overrideExitCode(exitCode); } - - /// Implement a mode for use in `dartdev run`. - /// - /// Usage: `dartdev run [package[:command]]` - /// - /// If `package` is not given, defaults to current root package. - /// If `command` is not given, defaults to name of `package`. - /// - /// Runs `bin/<command>.dart` from package `<package>`. If `<package>` is not - /// mutable (local root package or path-dependency) a source snapshot will be - /// cached in - /// `.dart_tool/pub/bin/<package>/<command>.dart-<sdkVersion>.snapshot`. - Future<void> _runFromDartDev() async { - var package = entrypoint.root.name; - var command = package; - var args = <String>[]; - - if (argResults.rest.isNotEmpty) { - if (argResults.rest[0].contains(RegExp(r'[/\\]'))) { - usageException('[<package>[:command]] cannot contain "/" or "\\"'); - } - - package = argResults.rest[0]; - if (package.contains(':')) { - final parts = package.split(':'); - if (parts.length > 2) { - usageException('[<package>[:command]] cannot contain multiple ":"'); - } - package = parts[0]; - command = parts[1]; - } else { - command = package; - } - args = argResults.rest.skip(1).toList(); - } - - final vmArgs = vmArgsFromArgResults(argResults); - - overrideExitCode( - await runExecutable( - entrypoint, - Executable(package, 'bin/$command.dart'), - args, - vmArgs: vmArgs, - enableAsserts: argResults['enable-asserts'] || argResults['checked'], - recompile: entrypoint.precompileExecutable, - alwaysUseSubprocess: alwaysUseSubprocess, - ), - ); - } }
diff --git a/lib/src/command/serve.dart b/lib/src/command/serve.dart index 76c0002..4c560e7 100644 --- a/lib/src/command/serve.dart +++ b/lib/src/command/serve.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'barback.dart'; /// Handles the `serve` pub command.
diff --git a/lib/src/command/token.dart b/lib/src/command/token.dart index dafa88f..9886dcf 100644 --- a/lib/src/command/token.dart +++ b/lib/src/command/token.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.11 - import '../command.dart'; import 'token_add.dart'; import 'token_list.dart';
diff --git a/lib/src/command/token_add.dart b/lib/src/command/token_add.dart index f7cd6b9..caf3b8b 100644 --- a/lib/src/command/token_add.dart +++ b/lib/src/command/token_add.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.11 - import 'dart:async'; import 'dart:io'; @@ -26,7 +24,7 @@ @override String get argumentsDescription => '[hosted-url]'; - String get envVar => argResults['env-var']; + String? get envVar => argResults['env-var']; TokenAddCommand() { argParser.addOption('env-var', @@ -42,32 +40,28 @@ } else if (argResults.rest.length > 1) { usageException('Takes only a single argument.'); } + final rawHostedUrl = argResults.rest.first; try { - var hostedUrl = validateAndNormalizeHostedUrl(argResults.rest.first); - if (hostedUrl.isScheme('HTTP')) { - throw DataException('Insecure package repository could not be added.'); + var hostedUrl = validateAndNormalizeHostedUrl(rawHostedUrl); + if (!hostedUrl.isScheme('HTTPS')) { + throw FormatException('url must be https://, ' + 'insecure repositories cannot use authentication.'); } if (envVar == null) { await _addTokenFromStdin(hostedUrl); } else { - await _addEnvVarToken(hostedUrl); + await _addEnvVarToken(hostedUrl, envVar!); } } on FormatException catch (e) { - usageException('Invalid [hosted-url]: "${argResults.rest.first}"\n' + usageException('Invalid [hosted-url]: "$rawHostedUrl"\n' '${e.message}'); - } on TimeoutException catch (_) { - // Timeout is added to readLine call to make sure automated jobs doesn't - // get stuck on noop state if user forget to pipe token to the 'token add' - // command. This behavior might be removed. - throw ApplicationException('Token is not provided within 15 minutes.'); } } Future<void> _addTokenFromStdin(Uri hostedUrl) async { - final token = await stdinPrompt('Enter secret token:', echoMode: false) - .timeout(const Duration(minutes: 15)); + final token = await stdinPrompt('Enter secret token:', echoMode: false); if (token.isEmpty) { usageException('Token is not provided.'); } @@ -79,22 +73,45 @@ ); } - Future<void> _addEnvVarToken(Uri hostedUrl) async { + Future<void> _addEnvVarToken(Uri hostedUrl, String envVar) async { if (envVar.isEmpty) { - throw DataException('Cannot use the empty string as --env-var'); + usageException('Cannot use the empty string as --env-var'); + } + + // Environment variable names on Windows [1] and UNIX [2] cannot contain + // equal signs. + // [1] https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables + // [2] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html + if (envVar.contains('=')) { + throw DataException( + 'Environment variable name --env-var="$envVar" cannot contain "=", the ' + 'equals sign is not allowed in environment variable names.', + ); + } + + // Help the user if they typed something that is unlikely to be correct. + // This could happen if you include $, whitespace, quotes or accidentally + // dereference the environment variable instead. + if (!RegExp(r'^[A-Z_][A-Z0-9_]*$').hasMatch(envVar)) { + log.warning( + 'The environment variable name --env-var="$envVar" does not use ' + 'uppercase characters A-Z, 0-9 and underscore. This is unusual for ' + 'environment variable names.\n' + 'Check that you meant to use the environment variable name: "$envVar".', + ); } tokenStore.addCredential(Credential.env(hostedUrl, envVar)); log.message( 'Requests to "$hostedUrl" will now be authenticated using the secret ' - 'token stored in the environment variable `$envVar`.', + 'token stored in the environment variable "$envVar".', ); if (!Platform.environment.containsKey(envVar)) { // If environment variable doesn't exist when // pub token add <hosted-url> --env-var <ENV_VAR> is called, we should // print a warning. - log.warning('Environment variable `$envVar` is not defined.'); + log.warning('Environment variable "$envVar" is not defined.'); } } }
diff --git a/lib/src/command/token_list.dart b/lib/src/command/token_list.dart index 828f004..3cf73ee 100644 --- a/lib/src/command/token_list.dart +++ b/lib/src/command/token_list.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.11 - import '../command.dart'; import '../log.dart' as log;
diff --git a/lib/src/command/token_remove.dart b/lib/src/command/token_remove.dart index 7c49a0d..1b08127 100644 --- a/lib/src/command/token_remove.dart +++ b/lib/src/command/token_remove.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.11 - import '../command.dart'; import '../exceptions.dart'; import '../log.dart' as log;
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart index 39a42c7..0dc5fb7 100644 --- a/lib/src/command/upgrade.dart +++ b/lib/src/command/upgrade.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; @@ -58,6 +56,9 @@ argParser.addFlag('packages-dir', hide: true); + argParser.addFlag('legacy-packages-file', + help: 'Generate the legacy ".packages" file', negatable: false); + argParser.addFlag( 'major-versions', help: 'Upgrades packages to their latest resolvable versions, ' @@ -82,6 +83,8 @@ bool get _precompile => argResults['precompile']; + bool get _packagesFile => argResults['legacy-packages-file']; + bool get _upgradeNullSafety => argResults['nullsafety'] || argResults['null-safety']; @@ -116,18 +119,21 @@ if (argResults['example'] && entrypoint.example != null) { // Reload the entrypoint to ensure we pick up potential changes that has // been made. - final exampleEntrypoint = Entrypoint(directory, cache).example; + final exampleEntrypoint = Entrypoint(directory, cache).example!; await _runUpgrade(exampleEntrypoint, onlySummary: true); } } Future<void> _runUpgrade(Entrypoint e, {bool onlySummary = false}) async { - await e.acquireDependencies(SolveType.UPGRADE, - unlock: argResults.rest, - dryRun: _dryRun, - precompile: _precompile, - onlyReportSuccessOrFailure: onlySummary); - + await e.acquireDependencies( + SolveType.upgrade, + unlock: argResults.rest, + dryRun: _dryRun, + precompile: _precompile, + onlyReportSuccessOrFailure: onlySummary, + generateDotPackages: _packagesFile, + analytics: analytics, + ); _showOfflineWarning(); } @@ -179,12 +185,12 @@ final resolvedPackages = <String, PackageId>{}; final solveResult = await log.spinner('Resolving dependencies', () async { return await resolveVersions( - SolveType.UPGRADE, + SolveType.upgrade, cache, Package.inMemory(resolvablePubspec), ); }, condition: _shouldShowSpinner); - for (final resolvedPackage in solveResult?.packages ?? []) { + for (final resolvedPackage in solveResult.packages) { resolvedPackages[resolvedPackage.name] = resolvedPackage; } @@ -196,9 +202,8 @@ ...entrypoint.root.pubspec.devDependencies.values, ].where((dep) => dep.source is HostedSource); for (final dep in declaredHostedDependencies) { - final resolvedPackage = resolvedPackages[dep.name]; - assert(resolvedPackage != null); - if (resolvedPackage == null || !toUpgrade.contains(dep.name)) { + final resolvedPackage = resolvedPackages[dep.name]!; + if (!toUpgrade.contains(dep.name)) { // If we're not to upgrade this package, or it wasn't in the // resolution somehow, then we ignore it. continue; @@ -219,30 +224,37 @@ resolvedPackage.version, )); } + final newPubspecText = _updatePubspec(changes); if (_dryRun) { // Even if it is a dry run, run `acquireDependencies` so that the user // gets a report on changes. - // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output - await Entrypoint.global( - Package.inMemory(resolvablePubspec), - entrypoint.lockFile, + await Entrypoint.inMemory( + Package.inMemory( + Pubspec.parse(newPubspecText, cache.sources), + ), cache, + lockFile: entrypoint.lockFile, solveResult: solveResult, ).acquireDependencies( - SolveType.UPGRADE, + SolveType.get, dryRun: true, precompile: _precompile, + analytics: null, // No analytics for dry-run + generateDotPackages: false, ); } else { - await _updatePubspec(changes); - + if (changes.isNotEmpty) { + writeTextFile(entrypoint.pubspecPath, newPubspecText); + } // TODO: Allow Entrypoint to be created with in-memory pubspec, so that // we can show the changes when not in --dry-run mode. For now we only show // the changes made to pubspec.yaml in dry-run mode. await Entrypoint(directory, cache).acquireDependencies( - SolveType.UPGRADE, + SolveType.get, precompile: _precompile, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], ); } @@ -275,12 +287,12 @@ final resolvedPackages = <String, PackageId>{}; final solveResult = await log.spinner('Resolving dependencies', () async { return await resolveVersions( - SolveType.UPGRADE, + SolveType.upgrade, cache, Package.inMemory(nullsafetyPubspec), ); }, condition: _shouldShowSpinner); - for (final resolvedPackage in solveResult?.packages ?? []) { + for (final resolvedPackage in solveResult.packages) { resolvedPackages[resolvedPackage.name] = resolvedPackage; } @@ -292,9 +304,8 @@ ...entrypoint.root.pubspec.devDependencies.values, ].where((dep) => dep.source is HostedSource); for (final dep in declaredHostedDependencies) { - final resolvedPackage = resolvedPackages[dep.name]; - assert(resolvedPackage != null); - if (resolvedPackage == null || !toUpgrade.contains(dep.name)) { + final resolvedPackage = resolvedPackages[dep.name]!; + if (!toUpgrade.contains(dep.name)) { // If we're not to upgrade this package, or it wasn't in the // resolution somehow, then we ignore it. continue; @@ -313,29 +324,35 @@ changes[dep] = dep.withConstraint(constraint); } + final newPubspecText = _updatePubspec(changes); if (_dryRun) { // Even if it is a dry run, run `acquireDependencies` so that the user // gets a report on changes. // TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output - await Entrypoint.global( - Package.inMemory(nullsafetyPubspec), - entrypoint.lockFile, + await Entrypoint.inMemory( + Package.inMemory(Pubspec.parse(newPubspecText, cache.sources)), cache, + lockFile: entrypoint.lockFile, solveResult: solveResult, ).acquireDependencies( - SolveType.UPGRADE, + SolveType.upgrade, dryRun: true, precompile: _precompile, + analytics: null, + generateDotPackages: false, ); } else { - await _updatePubspec(changes); - + if (changes.isNotEmpty) { + writeTextFile(entrypoint.pubspecPath, newPubspecText); + } // TODO: Allow Entrypoint to be created with in-memory pubspec, so that // we can show the changes in --dry-run mode. For now we only show // the changes made to pubspec.yaml in dry-run mode. await Entrypoint(directory, cache).acquireDependencies( - SolveType.UPGRADE, + SolveType.upgrade, precompile: _precompile, + analytics: analytics, + generateDotPackages: argResults['legacy-packages-file'], ); } @@ -353,10 +370,9 @@ ...entrypoint.root.pubspec.devDependencies.keys ]; await Future.wait(directDeps.map((name) async { - final resolvedPackage = resolvedPackages[name]; - assert(resolvedPackage != null); + final resolvedPackage = resolvedPackages[name]!; - final boundSource = resolvedPackage.source.bind(cache); + final boundSource = resolvedPackage.source!.bind(cache); final pubspec = await boundSource.describe(resolvedPackage); if (!pubspec.languageVersion.supportsNullSafety) { nonMigratedDirectDeps.add(name); @@ -380,13 +396,11 @@ } /// Updates `pubspec.yaml` with given [changes]. - Future<void> _updatePubspec( + String _updatePubspec( Map<PackageRange, PackageRange> changes, - ) async { + ) { ArgumentError.checkNotNull(changes, 'changes'); - if (changes.isEmpty) return; - final yamlEditor = YamlEditor(readTextFile(entrypoint.pubspecPath)); final deps = entrypoint.root.pubspec.dependencies.keys; final devDeps = entrypoint.root.pubspec.devDependencies.keys; @@ -406,9 +420,7 @@ ); } } - - /// Windows line endings are already handled by [yamlEditor] - writeTextFile(entrypoint.pubspecPath, yamlEditor.toString()); + return yamlEditor.toString(); } /// Outputs a summary of changes made to `pubspec.yaml`. @@ -468,7 +480,7 @@ return dep; } - final boundSource = dep.source.bind(cache); + final boundSource = dep.source!.bind(cache); final packages = await boundSource.getVersions(dep.toRef()); packages.sort((a, b) => a.version.compareTo(b.version)); @@ -483,7 +495,9 @@ } hasNoNullSafetyVersions.add(dep.name); - return null; + // This value is never used. We will throw an exception because + //`hasNonNullSafetyVersions` is not empty. + return dep.withConstraint(VersionConstraint.empty); })); final deps = _removeUpperConstraints(original.dependencies.values);
diff --git a/lib/src/command/uploader.dart b/lib/src/command/uploader.dart index 2498eea..99a6a57 100644 --- a/lib/src/command/uploader.dart +++ b/lib/src/command/uploader.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io';
diff --git a/lib/src/command/version.dart b/lib/src/command/version.dart index 51eeb8f..2ac96e7 100644 --- a/lib/src/command/version.dart +++ b/lib/src/command/version.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../command.dart'; import '../log.dart' as log; import '../sdk.dart';
diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index 8bfa25b..7c8b041 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart
@@ -2,20 +2,18 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:path/path.dart' as p; -import 'package:pub/src/command/dependency_services.dart'; import 'command.dart' show PubTopLevel, lineLength; import 'command/add.dart'; import 'command/build.dart'; import 'command/cache.dart'; +import 'command/dependency_services.dart'; import 'command/deps.dart'; import 'command/downgrade.dart'; import 'command/get.dart'; @@ -48,45 +46,53 @@ class PubCommandRunner extends CommandRunner<int> implements PubTopLevel { @override - String get directory => _argResults['directory']; + String? get directory => argResults['directory']; @override bool get captureStackChains { - return _argResults['trace'] || - _argResults['verbose'] || - _argResults['verbosity'] == 'all'; + return argResults['trace'] || + argResults['verbose'] || + argResults['verbosity'] == 'all'; } @override Verbosity get verbosity { - switch (_argResults['verbosity']) { + switch (argResults['verbosity']) { case 'error': - return log.Verbosity.ERROR; + return log.Verbosity.error; case 'warning': - return log.Verbosity.WARNING; + return log.Verbosity.warning; case 'normal': - return log.Verbosity.NORMAL; + return log.Verbosity.normal; case 'io': - return log.Verbosity.IO; + return log.Verbosity.io; case 'solver': - return log.Verbosity.SOLVER; + return log.Verbosity.solver; case 'all': - return log.Verbosity.ALL; + return log.Verbosity.all; default: // No specific verbosity given, so check for the shortcut. - if (_argResults['verbose']) return log.Verbosity.ALL; - return log.Verbosity.NORMAL; + if (argResults['verbose']) return log.Verbosity.all; + if (runningFromTest) return log.Verbosity.testing; + return log.Verbosity.normal; } } @override - bool get trace => _argResults['trace']; + bool get trace => argResults['trace']; - ArgResults _argResults; + ArgResults? _argResults; /// The top-level options parsed by the command runner. @override - ArgResults get argResults => _argResults; + ArgResults get argResults { + final a = _argResults; + if (a == null) { + throw StateError( + 'argResults cannot be used before Command.run is called.'); + } + return a; + } @override String get usageFooter => @@ -152,7 +158,7 @@ Future<int> run(Iterable<String> args) async { try { _argResults = parse(args); - return await runCommand(_argResults) ?? exit_codes.SUCCESS; + return await runCommand(argResults) ?? exit_codes.SUCCESS; } on UsageException catch (error) { log.exception(error); return exit_codes.USAGE; @@ -160,7 +166,7 @@ } @override - Future<int> runCommand(ArgResults topLevelResults) async { + Future<int?> runCommand(ArgResults topLevelResults) async { _checkDepsSynced(); if (topLevelResults['version']) {
diff --git a/lib/src/dart.dart b/lib/src/dart.dart index e498058..f4f8686 100644 --- a/lib/src/dart.dart +++ b/lib/src/dart.dart
@@ -7,8 +7,7 @@ import 'dart:io'; import 'package:analyzer/dart/analysis/analysis_context.dart'; -import 'package:analyzer/dart/analysis/context_builder.dart'; -import 'package:analyzer/dart/analysis/context_locator.dart'; +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/session.dart'; import 'package:analyzer/dart/ast/ast.dart'; @@ -67,21 +66,22 @@ modificationStamp: 0, ); + var contextCollection = AnalysisContextCollection( + includedPaths: [path], + resourceProvider: resourceProvider, + sdkPath: getSdkPath(), + ); + // Add new contexts for the given path. - var contextLocator = ContextLocator(resourceProvider: resourceProvider); - var roots = contextLocator.locateRoots(includedPaths: [path]); - for (var root in roots) { - var contextRootPath = root.root.path; + for (var analysisContext in contextCollection.contexts) { + var contextRootPath = analysisContext.contextRoot.root.path; // If there is already a context for this context root path, keep it. if (_contexts.containsKey(contextRootPath)) { continue; } - var contextBuilder = ContextBuilder(); - var context = contextBuilder.createContext( - contextRoot: root, sdkPath: getSdkPath()); - _contexts[contextRootPath] = context; + _contexts[contextRootPath] = analysisContext; } } @@ -94,7 +94,7 @@ /// Throws [AnalyzerErrorGroup] is the file has parsing errors. CompilationUnit parse(String path) { path = p.normalize(p.absolute(path)); - var parseResult = _getExistingSession(path).getParsedUnit2(path); + var parseResult = _getExistingSession(path).getParsedUnit(path); if (parseResult is ParsedUnitResult) { if (parseResult.errors.isNotEmpty) { throw AnalyzerErrorGroup(parseResult.errors); @@ -146,11 +146,14 @@ String toString() => errors.join('\n'); } -/// Precompiles the Dart executable at [executablePath] to a kernel file at -/// [outputPath]. +/// Precompiles the Dart executable at [executablePath]. /// -/// This file is also cached at [incrementalDillOutputPath] which is used to -/// initialize the compiler on future runs. +/// If the compilation succeeds it is saved to a kernel file at [outputPath]. +/// +/// If compilation fails, the output is cached at [incrementalDillOutputPath]. +/// +/// Whichever of [incrementalDillOutputPath] and [outputPath] already exists is +/// used to initialize the compiler run. /// /// The [packageConfigPath] should point at the package config file to be used /// for `package:` uri resolution. @@ -158,39 +161,65 @@ /// The [name] is used to describe the executable in logs and error messages. Future<void> precompile({ required String executablePath, - required String incrementalDillOutputPath, + required String incrementalDillPath, required String name, required String outputPath, required String packageConfigPath, }) async { ensureDir(p.dirname(outputPath)); - ensureDir(p.dirname(incrementalDillOutputPath)); + ensureDir(p.dirname(incrementalDillPath)); + const platformDill = 'lib/_internal/vm_platform_strong.dill'; final sdkRoot = p.relative(p.dirname(p.dirname(Platform.resolvedExecutable))); - var client = await FrontendServerClient.start( - executablePath, - incrementalDillOutputPath, - platformDill, - sdkRoot: sdkRoot, - packagesJson: packageConfigPath, - printIncrementalDependencies: false, - ); + String? tempDir; + FrontendServerClient? client; try { - var result = await client.compile(); + tempDir = createTempDir(p.dirname(incrementalDillPath), 'tmp'); + // To avoid potential races we copy the incremental data to a temporary file + // for just this compilation. + final temporaryIncrementalDill = + p.join(tempDir, '${p.basename(incrementalDillPath)}.incremental.dill'); + try { + if (fileExists(incrementalDillPath)) { + copyFile(incrementalDillPath, temporaryIncrementalDill); + } else if (fileExists(outputPath)) { + copyFile(outputPath, temporaryIncrementalDill); + } + } on FileSystemException { + // Not able to copy existing file, compilation will start from scratch. + } + + client = await FrontendServerClient.start( + executablePath, + temporaryIncrementalDill, + platformDill, + sdkRoot: sdkRoot, + packagesJson: packageConfigPath, + printIncrementalDependencies: false, + ); + final result = await client.compile(); final highlightedName = log.bold(name); if (result?.errorCount == 0) { log.message('Built $highlightedName.'); - await File(incrementalDillOutputPath).copy(outputPath); + // By using rename we ensure atomicity. An external observer will either + // see the old or the new snapshot. + renameFile(temporaryIncrementalDill, outputPath); } else { - // Don't leave partial results. - deleteEntry(outputPath); + // By using rename we ensure atomicity. An external observer will either + // see the old or the new snapshot. + renameFile(temporaryIncrementalDill, incrementalDillPath); + // If compilation failed we don't want to leave an incorrect snapshot. + tryDeleteEntry(outputPath); throw ApplicationException( log.yellow('Failed to build $highlightedName:\n') + (result?.compilerOutputLines.join('\n') ?? '')); } } finally { - client.kill(); + client?.kill(); + if (tempDir != null) { + tryDeleteEntry(tempDir); + } } }
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index 8820c33..202580c 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -12,12 +10,12 @@ import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; +import 'package:yaml/yaml.dart'; import 'command_runner.dart'; import 'dart.dart' as dart; import 'exceptions.dart'; import 'executable.dart'; -import 'http.dart' as http; import 'io.dart'; import 'language_version.dart'; import 'lock_file.dart'; @@ -28,6 +26,7 @@ import 'package_graph.dart'; import 'package_name.dart'; import 'packages_file.dart' as packages_file; +import 'pub_embeddable_command.dart'; import 'pubspec.dart'; import 'sdk.dart'; import 'solver.dart'; @@ -73,78 +72,81 @@ /// but may be the entrypoint when you're running its tests. class Entrypoint { /// The root package this entrypoint is associated with. + /// + /// For a global package, this is the activated package. final Package root; + /// For a global package, this is the directory that the package is installed + /// in. Non-global packages have null. + final String? globalDir; + /// The system-wide cache which caches packages that need to be fetched over /// the network. final SystemCache cache; /// Whether this entrypoint exists within the package cache. - bool get isCached => root.dir != null && p.isWithin(cache.rootDir, root.dir); + bool get isCached => !root.isInMemory && p.isWithin(cache.rootDir, root.dir); /// Whether this is an entrypoint for a globally-activated package. - final bool isGlobal; + // final bool isGlobal; + bool get isGlobal => globalDir != null; /// The lockfile for the entrypoint. /// /// If not provided to the entrypoint, it will be loaded lazily from disk. - LockFile get lockFile { - if (_lockFile != null) return _lockFile; + LockFile get lockFile => _lockFile ??= _loadLockFile(); + LockFile _loadLockFile() { if (!fileExists(lockFilePath)) { - _lockFile = LockFile.empty(); + return _lockFile = LockFile.empty(); } else { - _lockFile = LockFile.load(lockFilePath, cache.sources); + return _lockFile = LockFile.load(lockFilePath, cache.sources); } - - return _lockFile; } - LockFile _lockFile; + LockFile? _lockFile; /// The package graph for the application and all of its transitive /// dependencies. /// /// Throws a [DataError] if the `.dart_tool/package_config.json` file isn't /// up-to-date relative to the pubspec and the lockfile. - PackageGraph get packageGraph { - if (_packageGraph != null) return _packageGraph; + PackageGraph get packageGraph => _packageGraph ??= _createPackageGraph(); + PackageGraph _createPackageGraph() { assertUpToDate(); var packages = { for (var id in lockFile.packages.values) id.name: cache.load(id) }; packages[root.name] = root; - _packageGraph = PackageGraph(this, lockFile, packages); - return _packageGraph; + return PackageGraph(this, lockFile, packages); } - PackageGraph _packageGraph; + PackageGraph? _packageGraph; /// Where the lock file and package configurations are to be found. /// /// Global packages (except those from path source) /// store these in the global cache. - String get _configRoot => - isCached ? p.join(cache.rootDir, 'global_packages', root.name) : root.dir; + String? get _configRoot => isCached ? globalDir : root.dir; /// The path to the entrypoint's ".packages" file. /// /// This file is being slowly deprecated in favor of /// `.dart_tool/package_config.json`. Pub will still create it, but will /// not require it or make use of it within pub. - String get packagesFile => p.normalize(p.join(_configRoot, '.packages')); + String get packagesFile => p.normalize(p.join(_configRoot!, '.packages')); /// The path to the entrypoint's ".dart_tool/package_config.json" file. String get packageConfigFile => - p.normalize(p.join(_configRoot, '.dart_tool', 'package_config.json')); + p.normalize(p.join(_configRoot!, '.dart_tool', 'package_config.json')); /// The path to the entrypoint package's pubspec. String get pubspecPath => p.normalize(root.path('pubspec.yaml')); /// The path to the entrypoint package's lockfile. - String get lockFilePath => p.normalize(p.join(_configRoot, 'pubspec.lock')); + String get lockFilePath => p.normalize(p.join(_configRoot!, 'pubspec.lock')); /// The path to the entrypoint package's `.dart_tool/pub` cache directory. /// @@ -156,11 +158,7 @@ /// but the configuration is stored at the package itself. String get cachePath { if (isGlobal) { - return p.join( - cache.rootDir, - 'global_packages', - root.name, - ); + return globalDir!; } else { var newPath = root.path('.dart_tool/pub'); var oldPath = root.path('.pub'); @@ -177,15 +175,25 @@ String get _incrementalDillsPath => p.join(cachePath, 'incremental'); /// Loads the entrypoint from a package at [rootDir]. - Entrypoint(String rootDir, this.cache) - : root = Package.load(null, rootDir, cache.sources), - isGlobal = false; + Entrypoint( + String rootDir, + this.cache, + ) : root = Package.load(null, rootDir, cache.sources), + globalDir = null; + + Entrypoint.inMemory(this.root, this.cache, + {required LockFile? lockFile, SolveResult? solveResult}) + : _lockFile = lockFile, + globalDir = null { + if (solveResult != null) { + _packageGraph = PackageGraph.fromSolveResult(this, solveResult); + } + } /// Creates an entrypoint given package and lockfile objects. - /// If a SolveResult is already created it can be passes as an optimization. - Entrypoint.global(this.root, this._lockFile, this.cache, - {SolveResult solveResult}) - : isGlobal = true { + /// If a SolveResult is already created it can be passed as an optimization. + Entrypoint.global(this.globalDir, this.root, this._lockFile, this.cache, + {SolveResult? solveResult}) { if (solveResult != null) { _packageGraph = PackageGraph.fromSolveResult(this, solveResult); } @@ -194,7 +202,7 @@ /// Gets the [Entrypoint] package for the current working directory. /// /// This will be null if the example folder doesn't have a `pubspec.yaml`. - Entrypoint get example { + Entrypoint? get example { if (_example != null) return _example; if (!fileExists(root.path('example', 'pubspec.yaml'))) { return null; @@ -202,22 +210,28 @@ return _example = Entrypoint(root.path('example'), cache); } - Entrypoint _example; + Entrypoint? _example; /// Writes .packages and .dart_tool/package_config.json - Future<void> writePackagesFiles() async { - writeTextFile( - packagesFile, - lockFile.packagesFile(cache, - entrypoint: root.name, relativeFrom: root.dir)); + Future<void> writePackagesFiles({bool generateDotPackages = false}) async { + final entrypointName = isGlobal ? null : root.name; + if (generateDotPackages) { + writeTextFile( + packagesFile, + lockFile.packagesFile(cache, + entrypoint: entrypointName, + relativeFrom: isGlobal ? null : root.dir)); + } else { + tryDeleteEntry(packagesFile); + } ensureDir(p.dirname(packageConfigFile)); writeTextFile( packageConfigFile, await lockFile.packageConfigFile(cache, - entrypoint: root.name, + entrypoint: entrypointName, entrypointSdkConstraint: root.pubspec.sdkConstraints[sdk.identifier], - relativeFrom: root.dir)); + relativeFrom: isGlobal ? null : root.dir)); } /// Gets all dependencies of the [root] package. @@ -244,28 +258,29 @@ /// Updates [lockFile] and [packageRoot] accordingly. Future<void> acquireDependencies( SolveType type, { - Iterable<String> unlock, + Iterable<String>? unlock, bool dryRun = false, bool precompile = false, + required bool generateDotPackages, + required PubAnalytics? analytics, bool onlyReportSuccessOrFailure = false, }) async { - final suffix = root.dir == null || root.dir == '.' ? '' : ' in ${root.dir}'; + final suffix = root.isInMemory || root.dir == '.' ? '' : ' in ${root.dir}'; SolveResult result; try { result = await log.progress('Resolving dependencies$suffix', () async { - // We require an SDK constraint lower-bound as of Dart 2.12.0 - _checkSdkConstraintIsDefined(root.pubspec); + _checkSdkConstraint(root.pubspec); return resolveVersions( type, cache, root, lockFile: lockFile, - unlock: unlock, + unlock: unlock ?? [], ); }); } catch (e) { if (onlyReportSuccessOrFailure && (e is ApplicationException)) { - final directoryOption = root.dir == null || root.dir == '.' + final directoryOption = root.isInMemory || root.dir == '.' ? '' : ' --directory ${root.dir}'; throw ApplicationException( @@ -276,7 +291,7 @@ } // Log once about all overridden packages. - if (warnAboutPreReleaseSdkOverrides && result.pubspecs != null) { + if (warnAboutPreReleaseSdkOverrides) { var overriddenPackages = (result.pubspecs.values .where((pubspec) => pubspec.dartSdkWasOverridden) .map((pubspec) => pubspec.name) @@ -297,7 +312,7 @@ await result.showReport(type, cache); } if (!dryRun) { - await Future.wait(result.packages.map(_get)); + await result.downloadCachedPackages(cache); _saveLockFile(result); } if (onlyReportSuccessOrFailure) { @@ -307,15 +322,19 @@ } if (!dryRun) { + if (analytics != null) { + result.sendAnalytics(analytics); + } + /// Build a package graph from the version solver results so we don't /// have to reload and reparse all the pubspecs. _packageGraph = PackageGraph.fromSolveResult(this, result); - await writePackagesFiles(); + await writePackagesFiles(generateDotPackages: generateDotPackages); try { if (precompile) { - await precompileExecutables(changed: result.changedPackages); + await precompileExecutables(); } else { _deleteExecutableSnapshots(changed: result.changedPackages); } @@ -345,7 +364,7 @@ } } final r = root.immediateDependencies.keys.expand((packageName) { - final package = packageGraph.packages[packageName]; + final package = packageGraph.packages[packageName]!; return package.executablePaths .map((path) => Executable(packageName, path)); }).toList(); @@ -353,7 +372,7 @@ } /// Precompiles all [_builtExecutables]. - Future<void> precompileExecutables({Iterable<String> changed}) async { + Future<void> precompileExecutables() async { migrateCache(); final executables = _builtExecutables; @@ -378,7 +397,7 @@ /// Precompiles executable .dart file at [path] to a snapshot. Future<void> precompileExecutable(Executable executable) async { - return await log.progress('Building package executable', () async { + await log.progress('Building package executable', () async { ensureDir(p.dirname(pathOfExecutable(executable))); return waitAndPrintErrors([_precompileExecutable(executable)]); }); @@ -386,10 +405,11 @@ Future<void> _precompileExecutable(Executable executable) async { final package = executable.package; + await dart.precompile( executablePath: resolveExecutable(executable), outputPath: pathOfExecutable(executable), - incrementalDillOutputPath: incrementalDillPathOfExecutable(executable), + incrementalDillPath: incrementalDillPathOfExecutable(executable), packageConfigPath: packageConfigFile, name: '$package:${p.basenameWithoutExtension(executable.relativePath)}'); @@ -424,7 +444,7 @@ /// The absolute path of [executable] resolved relative to [this]. String resolveExecutable(Executable executable) { return p.join( - packageGraph.packages[executable.package].dir, + packageGraph.packages[executable.package]!.dir, executable.relativePath, ); } @@ -433,7 +453,7 @@ /// /// If [changed] is passed, only dependencies whose contents might be changed /// if one of the given packages changes will have their executables deleted. - void _deleteExecutableSnapshots({Iterable<String> changed}) { + void _deleteExecutableSnapshots({Iterable<String>? changed}) { if (!dirExists(_snapshotPath)) return; // If we don't know what changed, we can't safely re-use any snapshots. @@ -441,7 +461,8 @@ deleteEntry(_snapshotPath); return; } - changed = changed.toSet(); + var changedDeps = changed; + changedDeps = changedDeps.toSet(); // If the existing executable was compiled with a different SDK, we need to // recompile regardless of what changed. @@ -462,27 +483,12 @@ packageGraph.isPackageMutable(package) || packageGraph .transitiveDependencies(package) - .any((dep) => changed.contains(dep.name))) { + .any((dep) => changedDeps.contains(dep.name))) { deleteEntry(entry); } } } - /// Makes sure the package at [id] is locally available. - /// - /// This automatically downloads the package to the system-wide cache as well - /// if it requires network access to retrieve (specifically, if the package's - /// source is a [CachedSource]). - Future<void> _get(PackageId id) async { - return await http.withDependencyType(root.dependencyType(id.name), - () async { - if (id.isRoot) return; - - var source = cache.source(id.source); - if (source is CachedSource) await source.downloadToSystemCache(id); - }); - } - /// Throws a [DataError] if the `.dart_tool/package_config.json` file doesn't /// exist or if it's out-of-date relative to the lockfile or the pubspec. /// @@ -555,8 +561,8 @@ } for (var match in _sdkConstraint.allMatches(lockFileText)) { - var identifier = match[1] == 'sdk' ? 'dart' : match[1].trim(); - var sdk = sdks[identifier]; + var identifier = match[1] == 'sdk' ? 'dart' : match[1]!.trim(); + var sdk = sdks[identifier]!; // Don't complain if there's an SDK constraint for an unavailable SDK. For // example, the Flutter SDK being unavailable just means that we aren't @@ -564,8 +570,8 @@ // able to `pub run` non-Flutter tools even in a Flutter app. if (!sdk.isAvailable) continue; - var parsedConstraint = VersionConstraint.parse(match[2]); - if (!parsedConstraint.allows(sdk.version)) { + var parsedConstraint = VersionConstraint.parse(match[2]!); + if (!parsedConstraint.allows(sdk.version!)) { dataError('${sdk.name} ${sdk.version} is incompatible with your ' "dependencies' SDK constraints. Please run \"$topLevelProgram pub get\" again."); } @@ -709,7 +715,7 @@ final packagePathsMapping = <String, String>{}; for (final package in packages.keys) { - final packageUri = packages[package]; + final packageUri = packages[package]!; // Pub only generates "file:" and relative URIs. if (packageUri.scheme != 'file' && packageUri.scheme.isNotEmpty) { @@ -747,7 +753,7 @@ '"pub" version, please run "$topLevelProgram pub get".'); } - String packageConfigRaw; + late String packageConfigRaw; try { packageConfigRaw = readTextFile(packageConfigFile); } on FileException { @@ -755,7 +761,7 @@ 'The "$packageConfigFile" file does not exist, please run "$topLevelProgram pub get".'); } - PackageConfig cfg; + late PackageConfig cfg; try { cfg = PackageConfig.fromJson(json.decode(packageConfigRaw)); } on FormatException { @@ -844,7 +850,7 @@ final windowsLineEndings = fileExists(lockFilePath) && detectWindowsLineEndings(readTextFile(lockFilePath)); - final serialized = _lockFile.serialize(root.dir); + final serialized = lockFile.serialize(root.dir); writeTextFile(lockFilePath, windowsLineEndings ? serialized.replaceAll('\n', '\r\n') : serialized); } @@ -855,7 +861,7 @@ // Cached packages don't have these. if (isCached) return; - var oldPath = p.join(_configRoot, '.pub'); + var oldPath = p.join(_configRoot!, '.pub'); if (!dirExists(oldPath)) return; var newPath = root.path('.dart_tool/pub'); @@ -870,10 +876,11 @@ } /// We require an SDK constraint lower-bound as of Dart 2.12.0 - void _checkSdkConstraintIsDefined(Pubspec pubspec) { + /// + /// We don't allow unknown sdks. + void _checkSdkConstraint(Pubspec pubspec) { final dartSdkConstraint = pubspec.sdkConstraints['dart']; - if (dartSdkConstraint is! VersionRange || - (dartSdkConstraint is VersionRange && dartSdkConstraint.min == null)) { + if (dartSdkConstraint is! VersionRange || dartSdkConstraint.min == null) { // Suggest version range '>=2.10.0 <3.0.0', we avoid using: // [CompatibleWithVersionRange] because some pub versions don't support // caret syntax (e.g. '^2.10.0') @@ -901,6 +908,24 @@ See https://dart.dev/go/sdk-constraint '''); } + for (final sdk in pubspec.sdkConstraints.keys) { + if (!sdks.containsKey(sdk)) { + final environment = pubspec.fields.nodes['environment'] as YamlMap; + final keyNode = environment.nodes.entries + .firstWhere((e) => (e.key as YamlNode).value == sdk) + .key as YamlNode; + throw PubspecException(''' +$pubspecPath refers to an unknown sdk '$sdk'. + +Did you mean to add it as a dependency? + +Either remove the constraint, or upgrade to a version of pub that supports the +given sdk. + +See https://dart.dev/go/sdk-constraint +''', keyNode.span); + } + } } }
diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart index 82a5dac..fcde747 100644 --- a/lib/src/exceptions.dart +++ b/lib/src/exceptions.dart
@@ -11,7 +11,6 @@ import 'package:yaml/yaml.dart'; import 'dart.dart'; -import 'sdk.dart'; /// An exception class for exceptions that are intended to be seen by the user. /// @@ -89,18 +88,20 @@ /// that other code in pub can use this to show a more detailed explanation of /// why the package was being requested. class PackageNotFoundException extends WrappedException { - /// If this failure was caused by an SDK being unavailable, this is that SDK. - final Sdk? missingSdk; + /// A hint indicating an action the user could take to resolve this problem. + /// + /// This will be printed after the package resolution conflict. + final String? hint; PackageNotFoundException( String message, { Object? innerError, StackTrace? innerTrace, - this.missingSdk, + this.hint, }) : super(message, innerError, innerTrace); @override - String toString() => "Package doesn't exist ($message)."; + String toString() => 'Package not available ($message).'; } /// Returns whether [error] is a user-facing error object.
diff --git a/lib/src/executable.dart b/lib/src/executable.dart index 08722e5..3f8f6a9 100644 --- a/lib/src/executable.dart +++ b/lib/src/executable.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; import 'dart:isolate'; @@ -19,12 +17,12 @@ import 'isolate.dart' as isolate; import 'log.dart' as log; import 'log.dart'; +import 'pub_embeddable_command.dart'; import 'solver/type.dart'; import 'system_cache.dart'; import 'utils.dart'; -/// Code shared between `run` `global run` and `run --dartdev` for extracting -/// vm arguments from arguments. +/// Extracting vm arguments from arguments. List<String> vmArgsFromArgResults(ArgResults argResults) { final experiments = argResults['enable-experiment'] as List; return [ @@ -50,11 +48,11 @@ /// /// Returns the exit code of the spawned app. Future<int> runExecutable( - Entrypoint entrypoint, Executable executable, Iterable<String> args, + Entrypoint entrypoint, Executable executable, List<String> args, {bool enableAsserts = false, - Future<void> Function(Executable) recompile, + required Future<void> Function(Executable) recompile, List<String> vmArgs = const [], - @required bool alwaysUseSubprocess}) async { + required bool alwaysUseSubprocess}) async { final package = executable.package; // Make sure the package is an immediate dependency of the entrypoint or the @@ -103,18 +101,7 @@ await recompile(executable); } executablePath = snapshotPath; - } else { - if (executablePath == null) { - var message = - 'Could not find ${log.bold(p.normalize(executable.relativePath))}'; - if (entrypoint.isGlobal || package != entrypoint.root.name) { - message += ' in package ${log.bold(package)}'; - } - log.error('$message.'); - return exit_codes.NO_INPUT; - } } - // We use an absolute path here not because the VM insists but because it's // helpful for the subprocess to be able to spawn Dart with // Platform.executableArguments and have that work regardless of the working @@ -124,7 +111,7 @@ try { return await _runDartProgram( executablePath, - args, + args.toList(), packageConfigAbsolute, enableAsserts: enableAsserts, vmArgs: vmArgs, @@ -140,7 +127,7 @@ await recompile(executable); return await _runDartProgram( executablePath, - args, + args.toList(), packageConfigAbsolute, enableAsserts: enableAsserts, vmArgs: vmArgs, @@ -165,9 +152,9 @@ /// a new process will always be started. Future<int> _runDartProgram( String path, List<String> args, String packageConfig, - {bool enableAsserts, - List<String> vmArgs, - @required bool alwaysUseSubprocess}) async { + {bool enableAsserts = false, + List<String> vmArgs = const <String>[], + required bool alwaysUseSubprocess}) async { path = p.absolute(path); packageConfig = p.absolute(packageConfig); @@ -175,10 +162,8 @@ // That provides better signal handling, and possibly faster startup. if ((!alwaysUseSubprocess) && vmArgs.isEmpty) { var argList = args.toList(); - return await isolate.runUri(p.toUri(path), argList, null, - enableAsserts: enableAsserts, - automaticPackageResolution: packageConfig == null, - packageConfig: p.toUri(packageConfig)); + return await isolate.runUri(p.toUri(path), argList, '', + enableAsserts: enableAsserts, packageConfig: p.toUri(packageConfig)); } else { // By ignoring sigint, only the child process will get it when // they are sent to the current process group. That is what happens when @@ -218,7 +203,23 @@ } } -/// Returns the path to dart program/snapshot to invoke for running [descriptor] +/// The result of a `getExecutableForCommand` command resolution. +@sealed +class DartExecutableWithPackageConfig { + /// Can be a .dart file or a incremental snapshot. + final String executable; + + /// The package_config.json to run [executable] with. Or <null> if the VM + /// should find it according to the standard rules. + final String? packageConfig; + + DartExecutableWithPackageConfig({ + required this.executable, + required this.packageConfig, + }); +} + +/// Returns the dart program/snapshot to invoke for running [descriptor] /// resolved according to the package configuration of the package at [root] /// (defaulting to the current working directory). Using the pub-cache at /// [pubCacheDir] (defaulting to the default pub cache). @@ -236,7 +237,9 @@ /// [CommandResolutionFailedException]. /// /// * Otherwise if the current package resolution is outdated do an implicit -/// `pub get`, if that fails, throw a [CommandResolutionFailedException]. +/// `pub get`, if that fails, throw a [CommandResolutionFailedException]. +/// +/// This pub get will send analytics events to [analytics] if provided. /// /// * Otherwise let `<current>` be the name of the package at [root], and /// interpret [descriptor] as `[<package>][:<command>]`. @@ -251,7 +254,7 @@ /// * `` and `:` both resolves to `<current>:bin/<current>.dart` or /// `bin/<current>:main.dart`. /// -/// If that doesn't resolve as an existing file throw an exception. +/// If that doesn't resolve as an existing file, throw an exception. /// /// ## Snapshotting /// @@ -264,11 +267,12 @@ /// /// Throws an [CommandResolutionFailedException] if the command is not found or /// if the entrypoint is not up to date (requires `pub get`) and a `pub get`. -Future<String> getExecutableForCommand( +Future<DartExecutableWithPackageConfig> getExecutableForCommand( String descriptor, { bool allowSnapshot = true, - String root, - String pubCacheDir, + String? root, + String? pubCacheDir, + PubAnalytics? analytics, }) async { root ??= p.current; var asPath = descriptor; @@ -283,67 +287,128 @@ } final asDirectFile = p.join(root, asPath); - if (fileExists(asDirectFile)) return p.relative(asDirectFile, from: root); - if (!fileExists(p.join(root, 'pubspec.yaml'))) { - throw CommandResolutionFailedException('Could not find file `$descriptor`'); + if (fileExists(asDirectFile)) { + return DartExecutableWithPackageConfig( + executable: p.relative(asDirectFile, from: root), + packageConfig: null, + ); } + if (!fileExists(p.join(root, 'pubspec.yaml'))) { + throw CommandResolutionFailedException._( + 'Could not find file `$descriptor`', + CommandResolutionIssue.fileNotFound); + } + final entrypoint = Entrypoint(root, SystemCache(rootDir: pubCacheDir)); try { - final entrypoint = Entrypoint(root, SystemCache(rootDir: pubCacheDir)); + // TODO(sigurdm): it would be nicer with a 'isUpToDate' function. + entrypoint.assertUpToDate(); + } on DataException { try { - // TODO(sigurdm): it would be nicer with a 'isUpToDate' function. - entrypoint.assertUpToDate(); - } on DataException { await warningsOnlyUnlessTerminal( - () => entrypoint.acquireDependencies(SolveType.GET)); + () => entrypoint.acquireDependencies( + SolveType.get, + analytics: analytics, + generateDotPackages: false, + ), + ); + } on ApplicationException catch (e) { + throw CommandResolutionFailedException._( + e.toString(), CommandResolutionIssue.pubGetFailed); } + } - String command; - String package; - if (descriptor.contains(':')) { - final parts = descriptor.split(':'); - if (parts.length > 2) { - throw CommandResolutionFailedException( - '[<package>[:command]] cannot contain multiple ":"'); - } - package = parts[0]; - if (package.isEmpty) package = entrypoint.root.name; - command = parts[1]; - } else { - package = descriptor; - if (package.isEmpty) package = entrypoint.root.name; - command = package; + late final String command; + String package; + if (descriptor.contains(':')) { + final parts = descriptor.split(':'); + if (parts.length > 2) { + throw CommandResolutionFailedException._( + '[<package>[:command]] cannot contain multiple ":"', + CommandResolutionIssue.parseError, + ); } + package = parts[0]; + if (package.isEmpty) package = entrypoint.root.name; + command = parts[1]; + } else { + package = descriptor; + if (package.isEmpty) package = entrypoint.root.name; + command = package; + } - final executable = Executable(package, p.join('bin', '$command.dart')); - if (!entrypoint.packageGraph.packages.containsKey(package)) { - throw CommandResolutionFailedException( - 'Could not find package `$package` or file `$descriptor`'); - } - final path = entrypoint.resolveExecutable(executable); - if (!fileExists(path)) { - throw CommandResolutionFailedException( - 'Could not find `bin${p.separator}$command.dart` in package `$package`.'); - } - if (!allowSnapshot) { - return p.relative(path, from: root); - } else { - final snapshotPath = entrypoint.pathOfExecutable(executable); - if (!fileExists(snapshotPath) || - entrypoint.packageGraph.isPackageMutable(package)) { + if (!entrypoint.packageGraph.packages.containsKey(package)) { + throw CommandResolutionFailedException._( + 'Could not find package `$package` or file `$descriptor`', + CommandResolutionIssue.packageNotFound, + ); + } + final executable = Executable(package, p.join('bin', '$command.dart')); + final packageConfig = p.join('.dart_tool', 'package_config.json'); + + final path = entrypoint.resolveExecutable(executable); + if (!fileExists(path)) { + throw CommandResolutionFailedException._( + 'Could not find `bin${p.separator}$command.dart` in package `$package`.', + CommandResolutionIssue.noBinaryFound, + ); + } + if (!allowSnapshot) { + return DartExecutableWithPackageConfig( + executable: p.relative(path, from: root), + packageConfig: packageConfig, + ); + } else { + final snapshotPath = entrypoint.pathOfExecutable(executable); + if (!fileExists(snapshotPath) || + entrypoint.packageGraph.isPackageMutable(package)) { + try { await warningsOnlyUnlessTerminal( () => entrypoint.precompileExecutable(executable), ); + } on ApplicationException catch (e) { + throw CommandResolutionFailedException._( + e.toString(), + CommandResolutionIssue.compilationFailed, + ); } - return p.relative(snapshotPath, from: root); } - } on ApplicationException catch (e) { - throw CommandResolutionFailedException(e.toString()); + return DartExecutableWithPackageConfig( + executable: p.relative(snapshotPath, from: root), + packageConfig: packageConfig, + ); } } +/// Information on why no executable is returned. +enum CommandResolutionIssue { + /// The command string looked like a file (contained '.' '/' or '\\'), but no + /// such file exists. + fileNotFound, + + /// The command-string was '<package>:<binary>' or '<package>', and <package> + /// was not in dependencies. + packageNotFound, + + /// The command string was '<package>:<binary>' or ':<binary>' and <binary> + /// was not found. + noBinaryFound, + + /// Failed retrieving dependencies (pub get). + pubGetFailed, + + /// Pre-compilation of the binary failed. + compilationFailed, + + /// The command string did not have a valid form (eg. more than one ':'). + parseError, +} + +/// Indicates that a command string did not resolve to an executable. +@sealed class CommandResolutionFailedException implements Exception { final String message; - CommandResolutionFailedException(this.message); + final CommandResolutionIssue issue; + CommandResolutionFailedException._(this.message, this.issue); @override String toString() {
diff --git a/lib/src/exit_codes.dart b/lib/src/exit_codes.dart index e072ef2..c6acaf7 100644 --- a/lib/src/exit_codes.dart +++ b/lib/src/exit_codes.dart
@@ -2,6 +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. +// ignore_for_file: constant_identifier_names + /// Exit code constants. /// /// From [the BSD sysexits manpage][manpage]. Not every constant here is used,
diff --git a/lib/src/feature.dart b/lib/src/feature.dart index ca98bc1..94134ab 100644 --- a/lib/src/feature.dart +++ b/lib/src/feature.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; @@ -41,7 +39,7 @@ void enableFeature(Feature feature) { if (!enabledFeatures.add(feature)) return; for (var require in feature.requires) { - enableFeature(features[require]); + enableFeature(features[require]!); } } @@ -57,8 +55,8 @@ } Feature(this.name, Iterable<PackageRange> dependencies, - {Iterable<String> requires, - Map<String, VersionConstraint> sdkConstraints, + {Iterable<String>? requires, + Map<String, VersionConstraint>? sdkConstraints, this.onByDefault = true}) : dependencies = UnmodifiableListView(dependencies.toList()), requires = requires == null
diff --git a/lib/src/git.dart b/lib/src/git.dart index 8c86390..5fa7536 100644 --- a/lib/src/git.dart +++ b/lib/src/git.dart
@@ -2,11 +2,11 @@ // 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. -// @dart=2.10 - /// Helper functionality for invoking Git. import 'dart:async'; +import 'package:path/path.dart' as p; + import 'exceptions.dart'; import 'io.dart'; import 'log.dart' as log; @@ -47,7 +47,7 @@ /// Returns the stdout as a list of strings if it succeeded. Completes to an /// exception if it failed. Future<List<String>> run(List<String> args, - {String workingDir, Map<String, String> environment}) async { + {String? workingDir, Map<String, String>? environment}) async { if (!isInstalled) { fail('Cannot find a Git executable.\n' 'Please ensure Git is correctly installed.'); @@ -55,7 +55,7 @@ log.muteProgress(); try { - var result = await runProcess(command, args, + final result = await runProcess(command!, args, workingDir: workingDir, environment: {...?environment, 'LANG': 'en_GB'}); if (!result.success) { @@ -70,13 +70,13 @@ /// Like [run], but synchronous. List<String> runSync(List<String> args, - {String workingDir, Map<String, String> environment}) { + {String? workingDir, Map<String, String>? environment}) { if (!isInstalled) { fail('Cannot find a Git executable.\n' 'Please ensure Git is correctly installed.'); } - var result = runProcessSync(command, args, + final result = runProcessSync(command!, args, workingDir: workingDir, environment: environment); if (!result.success) { throw GitException(args, result.stdout.join('\n'), result.stderr.join('\n'), @@ -88,7 +88,7 @@ /// Returns the name of the git command-line app, or `null` if Git could not be /// found on the user's PATH. -String get command { +String? get command { if (_commandCache != null) return _commandCache; if (_tryGitCommand('git')) { @@ -103,7 +103,23 @@ return _commandCache; } -String _commandCache; +String? _commandCache; + +/// Returns the root of the git repo [dir] belongs to. Returns `null` if not +/// in a git repo or git is not installed. +String? repoRoot(String dir) { + if (isInstalled) { + try { + return p.normalize( + runSync(['rev-parse', '--show-toplevel'], workingDir: dir).first, + ); + } on GitException { + // Not in a git folder. + return null; + } + } + return null; +} /// Checks whether [command] is the Git command for this computer. bool _tryGitCommand(String command) {
diff --git a/lib/src/global_packages.dart b/lib/src/global_packages.dart index 49d681f..07e2513 100644 --- a/lib/src/global_packages.dart +++ b/lib/src/global_packages.dart
@@ -2,12 +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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; @@ -15,14 +12,15 @@ import 'entrypoint.dart'; import 'exceptions.dart'; import 'executable.dart' as exec; -import 'http.dart' as http; import 'io.dart'; import 'lock_file.dart'; import 'log.dart' as log; import 'package.dart'; import 'package_name.dart'; +import 'pub_embeddable_command.dart'; import 'pubspec.dart'; import 'sdk.dart'; +import 'sdk/dart.dart'; import 'solver.dart'; import 'solver/incompatibility_cause.dart'; import 'source/cached.dart'; @@ -63,6 +61,8 @@ /// The directory where the lockfiles for activated packages are stored. String get _directory => p.join(cache.rootDir, 'global_packages'); + String _packageDir(String packageName) => p.join(_directory, packageName); + /// The directory where binstubs for global package executables are stored. String get _binStubDir => p.join(cache.rootDir, 'bin'); @@ -85,8 +85,9 @@ /// If [overwriteBinStubs] is `true`, any binstubs that collide with /// existing binstubs in other packages will be overwritten by this one's. /// Otherwise, the previous ones will be preserved. - Future<void> activateGit(String repo, List<String> executables, - {Map<String, FeatureDependency> features, bool overwriteBinStubs}) async { + Future<void> activateGit(String repo, List<String>? executables, + {Map<String, FeatureDependency>? features, + required bool overwriteBinStubs}) async { var name = await cache.git.getPackageNameFromRepo(repo); // TODO(nweiz): Add some special handling for git repos that contain path @@ -121,10 +122,10 @@ /// [url] is an optional custom pub server URL. If not null, the package to be /// activated will be fetched from this URL instead of the default pub URL. Future<void> activateHosted( - String name, VersionConstraint constraint, List<String> executables, - {Map<String, FeatureDependency> features, - bool overwriteBinStubs, - Uri url}) async { + String name, VersionConstraint constraint, List<String>? executables, + {Map<String, FeatureDependency>? features, + required bool overwriteBinStubs, + Uri? url}) async { await _installInCache( cache.hosted.source .refFor(name, url: url) @@ -143,33 +144,31 @@ /// if [overwriteBinStubs] is `true`, any binstubs that collide with /// existing binstubs in other packages will be overwritten by this one's. /// Otherwise, the previous ones will be preserved. - Future<void> activatePath(String path, List<String> executables, - {bool overwriteBinStubs}) async { + Future<void> activatePath(String path, List<String>? executables, + {required bool overwriteBinStubs, + required PubAnalytics? analytics}) async { var entrypoint = Entrypoint(path, cache); // Get the package's dependencies. - await entrypoint.acquireDependencies(SolveType.GET); + await entrypoint.acquireDependencies( + SolveType.get, + analytics: analytics, + generateDotPackages: false, + ); var name = entrypoint.root.name; - - try { - var originalLockFile = - LockFile.load(_getLockFilePath(name), cache.sources); - // Call this just to log what the current active package is, if any. - _describeActive(originalLockFile, name); - } on IOException { - // Couldn't read the lock file. It probably doesn't exist. - } + _describeActive(name, cache); // Write a lockfile that points to the local package. var fullPath = canonicalize(entrypoint.root.dir); var id = cache.path.source.idFor(name, entrypoint.root.version, fullPath); + final tempDir = cache.createTempDir(); // TODO(rnystrom): Look in "bin" and display list of binaries that // user can run. - _writeLockFile(name, LockFile([id])); + _writeLockFile(tempDir, LockFile([id])); - var binDir = p.join(_directory, name, 'bin'); - if (dirExists(binDir)) deleteEntry(binDir); + tryDeleteEntry(_packageDir(name)); + tryRenameDir(tempDir, _packageDir(name)); _updateBinStubs(entrypoint, entrypoint.root, executables, overwriteBinStubs: overwriteBinStubs); @@ -177,17 +176,12 @@ } /// Installs the package [dep] and its dependencies into the system cache. - Future<void> _installInCache(PackageRange dep, List<String> executables, - {bool overwriteBinStubs}) async { - LockFile originalLockFile; - try { - originalLockFile = - LockFile.load(_getLockFilePath(dep.name), cache.sources); - // Call this just to log what the current active package is, if any. - _describeActive(originalLockFile, dep.name); - } on IOException { - // Couldn't read the lock file. It probably doesn't exist. - } + /// + /// If [silent] less logging will be printed. + Future<void> _installInCache(PackageRange dep, List<String>? executables, + {required bool overwriteBinStubs, bool silent = false}) async { + final name = dep.name; + LockFile? originalLockFile = _describeActive(name, cache); // Create a dummy package with just [dep] so we can do resolution on it. var root = Package.inMemory(Pubspec('pub global activate', @@ -199,104 +193,90 @@ // being available, report that as a [dataError]. SolveResult result; try { - result = await log.progress('Resolving dependencies', - () => resolveVersions(SolveType.GET, cache, root)); + result = await log.spinner( + 'Resolving dependencies', + () => resolveVersions(SolveType.get, cache, root), + condition: !silent, + ); } on SolveFailure catch (error) { for (var incompatibility in error.incompatibility.externalIncompatibilities) { if (incompatibility.cause != IncompatibilityCause.noVersions) continue; - if (incompatibility.terms.single.package.name != dep.name) continue; + if (incompatibility.terms.single.package.name != name) continue; dataError(error.toString()); } rethrow; } + // We want the entrypoint to be rooted at 'dep' not the dummy-package. + result.packages.removeWhere((id) => id.name == 'pub global activate'); final sameVersions = originalLockFile != null && originalLockFile.samePackageIds(result.lockFile); + final PackageId id = result.lockFile.packages[name]!; if (sameVersions) { log.message(''' -The package ${dep.name} is already activated at newest available version. -To recompile executables, first run `global deactivate ${dep.name}`. +The package $name is already activated at newest available version. +To recompile executables, first run `$topLevelProgram pub global deactivate $name`. '''); } else { - await result.showReport(SolveType.GET, cache); + // Only precompile binaries if we have a new resolution. + if (!silent) await result.showReport(SolveType.get, cache); + + await result.downloadCachedPackages(cache); + + final lockFile = result.lockFile; + final tempDir = cache.createTempDir(); + _writeLockFile(tempDir, lockFile); + + // Load the package graph from [result] so we don't need to re-parse all + // the pubspecs. + final entrypoint = Entrypoint.global( + tempDir, + cache.loadCached(id), + lockFile, + cache, + solveResult: result, + ); + + await entrypoint.writePackagesFiles(); + + await entrypoint.precompileExecutables(); + + tryDeleteEntry(_packageDir(name)); + tryRenameDir(tempDir, _packageDir(name)); } - - // Make sure all of the dependencies are locally installed. - await Future.wait(result.packages.map((id) { - return http.withDependencyType(root.dependencyType(id.name), () async { - if (id.isRoot) return; - - var source = cache.source(id.source); - if (source is CachedSource) await source.downloadToSystemCache(id); - }); - })); - - var lockFile = result.lockFile; - _writeLockFile(dep.name, lockFile); - await _writePackageConfigFiles(dep.name, lockFile); - - // We want the entrypoint to be rooted at 'dep' not the dummy-package. - result.packages.removeWhere((id) => id.name == 'pub global activate'); - - var id = lockFile.packages[dep.name]; - // Load the package graph from [result] so we don't need to re-parse all - // the pubspecs. final entrypoint = Entrypoint.global( - Package( - result.pubspecs[dep.name], - (cache.source(dep.source) as CachedSource).getDirectoryInCache(id), - ), - lockFile, + _packageDir(id.name), + cache.loadCached(id), + result.lockFile, cache, solveResult: result, ); - if (!sameVersions) { - // Only precompile binaries if we have a new resolution. - await entrypoint.precompileExecutables(); - } - _updateBinStubs( entrypoint, - cache.load(entrypoint.lockFile.packages[dep.name]), + cache.load(entrypoint.lockFile.packages[dep.name]!), executables, overwriteBinStubs: overwriteBinStubs, ); - - log.message('Activated ${_formatPackage(id)}.'); - } - - Future<void> _writePackageConfigFiles( - String package, LockFile lockFile) async { - // TODO(sigurdm): Use [Entrypoint.writePackagesFiles] instead. - final packagesFilePath = _getPackagesFilePath(package); - final packageConfigFilePath = _getPackageConfigFilePath(package); - final dir = p.dirname(packagesFilePath); - writeTextFile( - packagesFilePath, lockFile.packagesFile(cache, relativeFrom: dir)); - ensureDir(p.dirname(packageConfigFilePath)); - writeTextFile(packageConfigFilePath, - await lockFile.packageConfigFile(cache, relativeFrom: dir)); + if (!silent) log.message('Activated ${_formatPackage(id)}.'); } /// Finishes activating package [package] by saving [lockFile] in the cache. - void _writeLockFile(String package, LockFile lockFile) { - ensureDir(p.join(_directory, package)); - - // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it - // when Dart 1.6 is old enough that we don't think anyone will have these - // lockfiles anymore (issue 20703). - var oldPath = p.join(_directory, '$package.lock'); - if (fileExists(oldPath)) deleteEntry(oldPath); - - writeTextFile(_getLockFilePath(package), - lockFile.serialize(p.join(_directory, package))); + void _writeLockFile(String dir, LockFile lockFile) { + writeTextFile(p.join(dir, 'pubspec.lock'), lockFile.serialize(null)); } /// Shows the user the currently active package with [name], if any. - void _describeActive(LockFile lockFile, String name) { - var id = lockFile.packages[name]; + LockFile? _describeActive(String name, SystemCache cache) { + late final LockFile lockFile; + try { + lockFile = LockFile.load(_getLockFilePath(name), cache.sources); + } on IOException { + // Couldn't read the lock file. It probably doesn't exist. + return null; + } + var id = lockFile.packages[name]!; var source = id.source; if (source is GitSource) { @@ -311,6 +291,7 @@ log.message('Package ${log.bold(name)} is currently active at version ' '${log.bold(id.version)}.'); } + return lockFile; } /// Deactivates a previously-activated package named [name]. @@ -323,7 +304,7 @@ _deleteBinStubs(name); var lockFile = LockFile.load(_getLockFilePath(name), cache.sources); - var id = lockFile.packages[name]; + var id = lockFile.packages[name]!; log.message('Deactivated package ${_formatPackage(id)}.'); deleteEntry(dir); @@ -336,32 +317,18 @@ /// Returns an [Entrypoint] loaded with the active package if found. Future<Entrypoint> find(String name) async { var lockFilePath = _getLockFilePath(name); - LockFile lockFile; + late LockFile lockFile; try { lockFile = LockFile.load(lockFilePath, cache.sources); } on IOException { - var oldLockFilePath = p.join(_directory, '$name.lock'); - try { - // TODO(nweiz): This looks for Dart 1.6's old lockfile location. - // Remove it when Dart 1.6 is old enough that we don't think anyone - // will have these lockfiles anymore (issue 20703). - lockFile = LockFile.load(oldLockFilePath, cache.sources); - } on IOException { - // If we couldn't read the lock file, it's not activated. - dataError('No active package ${log.bold(name)}.'); - } - - // Move the old lockfile to its new location. - ensureDir(p.dirname(lockFilePath)); - File(oldLockFilePath).renameSync(lockFilePath); - // Just make sure these files are created as well. - await _writePackageConfigFiles(name, lockFile); + // If we couldn't read the lock file, it's not activated. + dataError('No active package ${log.bold(name)}.'); } // Remove the package itself from the lockfile. We put it in there so we // could find and load the [Package] object, but normally an entrypoint // doesn't expect to be in its own lockfile. - var id = lockFile.packages[name]; + var id = lockFile.packages[name]!; lockFile = lockFile.removePackage(name); var source = cache.source(id.source); @@ -369,7 +336,8 @@ if (source is CachedSource) { // For cached sources, the package itself is in the cache and the // lockfile is the one we just loaded. - entrypoint = Entrypoint.global(cache.loadCached(id), lockFile, cache); + entrypoint = Entrypoint.global( + _packageDir(id.name), cache.loadCached(id), lockFile, cache); } else { // For uncached sources (i.e. path), the ID just points to the real // directory for the package. @@ -383,7 +351,7 @@ dataError('${log.bold(name)} ${entrypoint.root.version} requires ' 'unknown SDK "$name".'); } else if (sdkName == 'dart') { - if (constraint.allows(sdk.version)) return; + if (constraint.allows((sdk as DartSdk).version)) return; dataError("${log.bold(name)} ${entrypoint.root.version} doesn't " 'support Dart ${sdk.version}.'); } else { @@ -399,7 +367,7 @@ dataError('${log.bold(name)} as globally activated requires ' 'unknown SDK "$name".'); } else if (sdkName == 'dart') { - if (constraint.allows(sdk.version)) return; + if (constraint.allows((sdk as DartSdk).version)) return; dataError("${log.bold(name)} as globally activated doesn't " 'support Dart ${sdk.version}, try: $topLevelProgram pub global activate $name'); } else { @@ -421,11 +389,11 @@ /// /// Returns the exit code from the executable. Future<int> runExecutable( - Entrypoint entrypoint, exec.Executable executable, Iterable<String> args, + Entrypoint entrypoint, exec.Executable executable, List<String> args, {bool enableAsserts = false, - Future<void> Function(exec.Executable) recompile, + required Future<void> Function(exec.Executable) recompile, List<String> vmArgs = const [], - @required bool alwaysUseSubprocess}) async { + required bool alwaysUseSubprocess}) async { return await exec.runExecutable( entrypoint, executable, @@ -445,16 +413,6 @@ String _getLockFilePath(String name) => p.join(_directory, name, 'pubspec.lock'); - /// Gets the path to the .packages file for an activated cached package with - /// [name]. - String _getPackagesFilePath(String name) => - p.join(_directory, name, '.packages'); - - /// Gets the path to the `package_config.json` file for an - /// activated cached package with [name]. - String _getPackageConfigFilePath(String name) => - p.join(_directory, name, '.dart_tool', 'package_config.json'); - /// Shows the user a formatted list of globally activated packages. void listActivePackages() { if (!dirExists(_directory)) return; @@ -535,23 +493,30 @@ var failures = <String>[]; if (dirExists(_directory)) { for (var entry in listDir(_directory)) { - PackageId id; + PackageId? id; try { id = _loadPackageId(entry); log.message('Reactivating ${log.bold(id.name)} ${id.version}...'); var entrypoint = await find(id.name); + final packageExecutables = executables.remove(id.name) ?? []; - await _writePackageConfigFiles(id.name, entrypoint.lockFile); - await entrypoint.precompileExecutables(); - var packageExecutables = executables.remove(id.name) ?? []; - _updateBinStubs( - entrypoint, - cache.load(id), - packageExecutables, - overwriteBinStubs: true, - suggestIfNotOnPath: false, - ); + if (entrypoint.isCached) { + deleteEntry(entrypoint.globalDir!); + await _installInCache( + id.toRange(), + packageExecutables, + overwriteBinStubs: true, + silent: true, + ); + } else { + await activatePath( + entrypoint.root.dir, + packageExecutables, + overwriteBinStubs: true, + analytics: null, + ); + } successes.add(id.name); } catch (error, stackTrace) { var message = 'Failed to reactivate ' @@ -631,8 +596,8 @@ /// If [suggestIfNotOnPath] is `true` (the default), this will warn the user if /// the bin directory isn't on their path. void _updateBinStubs( - Entrypoint entrypoint, Package package, List<String> executables, - {bool overwriteBinStubs, bool suggestIfNotOnPath = true}) { + Entrypoint entrypoint, Package package, List<String>? executables, + {required bool overwriteBinStubs, bool suggestIfNotOnPath = true}) { // Remove any previously activated binstubs for this package, in case the // list of executables has changed. _deleteBinStubs(package.name); @@ -650,7 +615,7 @@ for (var executable in allExecutables) { if (executables != null && !executables.contains(executable)) continue; - var script = package.pubspec.executables[executable]; + var script = package.pubspec.executables[executable]!; var previousPackage = _createBinStub( package, @@ -705,10 +670,7 @@ // Show errors for any missing scripts. // TODO(rnystrom): This can print false positives since a script may be // produced by a transformer. Do something better. - var binFiles = package - .listFiles(beneath: 'bin', recursive: false) - .map(package.relative) - .toList(); + var binFiles = package.executablePaths; for (var executable in installed) { var script = package.pubspec.executables[executable]; var scriptPath = p.join('bin', '$script.dart'); @@ -734,19 +696,19 @@ /// /// If a collision occurs, returns the name of the package that owns the /// existing binstub. Otherwise returns `null`. - String _createBinStub( + String? _createBinStub( Package package, String executable, String script, { - @required bool overwrite, - @required String snapshot, + required bool overwrite, + required String snapshot, }) { var binStubPath = p.join(_binStubDir, executable); if (Platform.isWindows) binStubPath += '.bat'; // See if the binstub already exists. If so, it's for another package // since we already deleted all of this package's binstubs. - String previousPackage; + String? previousPackage; if (fileExists(binStubPath)) { var contents = readTextFile(binStubPath); previousPackage = _binStubProperty(contents, 'Package'); @@ -760,8 +722,9 @@ // If the script was built to a snapshot, just try to invoke that // directly and skip pub global run entirely. String invocation; + late String binstub; if (Platform.isWindows) { - if (snapshot != null && fileExists(snapshot)) { + if (fileExists(snapshot)) { // We expect absolute paths from the precompiler since relative ones // won't be relative to the right directory when the user runs this. assert(p.isAbsolute(snapshot)); @@ -785,7 +748,7 @@ } else { invocation = 'dart pub global run ${package.name}:$script %*'; } - var batch = ''' + binstub = ''' @echo off rem This file was created by pub v${sdk.version}. rem Package: ${package.name} @@ -794,9 +757,8 @@ rem Script: $script $invocation '''; - writeTextFile(binStubPath, batch); } else { - if (snapshot != null && fileExists(snapshot)) { + if (fileExists(snapshot)) { // We expect absolute paths from the precompiler since relative ones // won't be relative to the right directory when the user runs this. assert(p.isAbsolute(snapshot)); @@ -817,7 +779,7 @@ } else { invocation = 'dart pub global run ${package.name}:$script "\$@"'; } - var bash = ''' + binstub = ''' #!/usr/bin/env sh # This file was created by pub v${sdk.version}. # Package: ${package.name} @@ -826,25 +788,31 @@ # Script: $script $invocation '''; + } - // Write this as the system encoding since the system is going to execute - // it and it might contain non-ASCII characters in the pathnames. - writeTextFile(binStubPath, bash, encoding: const SystemEncoding()); + // Write the binstub to a temporary location, make it executable and move + // it into place afterwards to avoid races. + final tempDir = cache.createTempDir(); + try { + final tmpPath = p.join(tempDir, binStubPath); - // Make it executable. - var result = Process.runSync('chmod', ['+x', binStubPath]); - if (result.exitCode != 0) { - // Couldn't make it executable so don't leave it laying around. - try { - deleteEntry(binStubPath); - } on IOException catch (err) { - // Do nothing. We're going to fail below anyway. - log.fine('Could not delete binstub:\n$err'); + // Write this as the system encoding since the system is going to + // execute it and it might contain non-ASCII characters in the + // pathnames. + writeTextFile(tmpPath, binstub, encoding: const SystemEncoding()); + + if (Platform.isLinux || Platform.isMacOS) { + // Make it executable. + var result = Process.runSync('chmod', ['+x', tmpPath]); + if (result.exitCode != 0) { + // Couldn't make it executable so don't leave it laying around. + fail('Could not make "$tmpPath" executable (exit code ' + '${result.exitCode}):\n${result.stderr}'); } - - fail('Could not make "$binStubPath" executable (exit code ' - '${result.exitCode}):\n${result.stderr}'); } + File(tmpPath).renameSync(binStubPath); + } finally { + deleteEntry(tempDir); } return previousPackage; @@ -896,7 +864,7 @@ if (result.exitCode == 0) return; var binDir = _binStubDir; - if (binDir.startsWith(Platform.environment['HOME'])) { + if (binDir.startsWith(Platform.environment['HOME']!)) { binDir = p.join( r'$HOME', p.relative(binDir, from: Platform.environment['HOME'])); } @@ -913,7 +881,7 @@ /// Returns the value of the property named [name] in the bin stub script /// [source]. - String _binStubProperty(String source, String name) { + String? _binStubProperty(String source, String name) { var pattern = RegExp(RegExp.escape(name) + r': ([a-zA-Z0-9_-]+)'); var match = pattern.firstMatch(source); return match == null ? null : match[1];
diff --git a/lib/src/http.dart b/lib/src/http.dart index 541931f..724962b 100644 --- a/lib/src/http.dart +++ b/lib/src/http.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - /// Helpers for dealing with HTTP. import 'dart:async'; import 'dart:convert'; @@ -12,7 +10,6 @@ import 'package:http/http.dart' as http; import 'package:http/retry.dart'; -import 'package:pedantic/pedantic.dart'; import 'package:pool/pool.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -44,7 +41,7 @@ http.Client _inner; - _PubHttpClient([http.Client inner]) : _inner = inner ?? http.Client(); + _PubHttpClient([http.Client? inner]) : _inner = inner ?? http.Client(); @override Future<http.StreamedResponse> send(http.BaseRequest request) async { @@ -132,8 +129,8 @@ // careful not to log OAuth2 private data, though. var responseLog = StringBuffer(); - var request = response.request; - var stopwatch = _requestStopwatches.remove(request)..stop(); + var request = response.request!; + var stopwatch = _requestStopwatches.remove(request)!..stop(); responseLog.writeln('HTTP response ${response.statusCode} ' '${response.reasonPhrase} for ${request.method} ${request.url}'); responseLog.writeln('took ${stopwatch.elapsed}'); @@ -173,12 +170,12 @@ @override Future<http.StreamedResponse> send(http.BaseRequest request) async { - http.StreamedResponse streamedResponse; + late http.StreamedResponse streamedResponse; try { streamedResponse = await _inner.send(request); } on SocketException catch (error, stackTraceOrNull) { // Work around issue 23008. - var stackTrace = stackTraceOrNull ?? Chain.current(); + var stackTrace = stackTraceOrNull; if (error.osError == null) rethrow; @@ -191,14 +188,14 @@ // with a retry. Failing to retry intermittent issues is likely to cause // customers to wrap pub in a retry loop which will not improve the // end-user experience. - if (error.osError.errorCode == 8 || - error.osError.errorCode == -2 || - error.osError.errorCode == -5 || - error.osError.errorCode == 11001 || - error.osError.errorCode == 11004) { + if (error.osError!.errorCode == 8 || + error.osError!.errorCode == -2 || + error.osError!.errorCode == -5 || + error.osError!.errorCode == 11001 || + error.osError!.errorCode == 11004) { fail('Could not resolve URL "${request.url.origin}".', error, stackTrace); - } else if (error.osError.errorCode == -12276) { + } else if (error.osError!.errorCode == -12276) { fail( 'Unable to validate SSL certificate for ' '"${request.url.origin}".', @@ -213,7 +210,7 @@ // 401 responses should be handled by the OAuth2 client. It's very // unlikely that they'll be returned by non-OAuth2 requests. We also want // to pass along 400 responses from the token endpoint. - var tokenRequest = streamedResponse.request.url == oauth2.tokenEndpoint; + var tokenRequest = streamedResponse.request!.url == oauth2.tokenEndpoint; if (status < 400 || status == 401 || (status == 400 && tokenRequest)) { return streamedResponse; } @@ -342,7 +339,7 @@ } /// Throws an error describing an invalid response from the server. -void invalidServerResponse(http.Response response) => +Never invalidServerResponse(http.Response response) => fail(log.red('Invalid server response:\n${response.body}')); /// Exception thrown when an HTTP operation fails.
diff --git a/lib/src/ignore.dart b/lib/src/ignore.dart index ade58d0..ff22dff 100644 --- a/lib/src/ignore.dart +++ b/lib/src/ignore.dart
@@ -94,7 +94,7 @@ /// [1]: https://git-scm.com/docs/gitignore /// [2]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreignoreCase Ignore( - Iterable<String> patterns, { + List<String> patterns, { bool ignoreCase = false, void Function(String pattern, FormatException exception)? onInvalidPattern, }) : _rules = _parseIgnorePatterns( @@ -464,6 +464,9 @@ } else { expr += '.*'; } + } else if (peekChar() == '/' || peekChar() == null) { + // /a/* should not match '/a/' + expr += '[^/]+'; } else { // Handle a single '*' expr += '[^/]*'; @@ -520,7 +523,6 @@ expr = '$expr/\$'; } else { expr = '$expr/?\$'; - // expr = '$expr\$'; } try { return _IgnoreParseResult(
diff --git a/lib/src/io.dart b/lib/src/io.dart index 9622eaa..280dcbd 100644 --- a/lib/src/io.dart +++ b/lib/src/io.dart
@@ -8,11 +8,12 @@ import 'dart:convert'; import 'dart:io'; +import 'package:cli_util/cli_util.dart' + show EnvironmentNotFoundException, applicationConfigHome; import 'package:http/http.dart' show ByteStream; import 'package:http_multi_server/http_multi_server.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -import 'package:pedantic/pedantic.dart'; import 'package:pool/pool.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -158,7 +159,9 @@ String readTextFile(String file) => File(file).readAsStringSync(); /// Reads the contents of the text file [file]. -Future<String> readTextFileAsync(String file) => File(file).readAsString(); +Future<String> readTextFileAsync(String file) { + return _descriptorPool.withResource(() => File(file).readAsString()); +} /// Reads the contents of the binary file [file]. List<int> readBinaryFile(String file) { @@ -358,52 +361,54 @@ /// when we try to delete or move something while it's being scanned. To /// mitigate that, on Windows, this will retry the operation a few times if it /// fails. -void _attempt(String description, void Function() operation) { +/// +/// For some operations it makes sense to handle ERROR_DIR_NOT_EMPTY +/// differently. They can pass [ignoreEmptyDir] = `true`. +void _attempt(String description, void Function() operation, + {bool ignoreEmptyDir = false}) { if (!Platform.isWindows) { operation(); return; } String? getErrorReason(FileSystemException error) { + // ERROR_ACCESS_DENIED if (error.osError?.errorCode == 5) { return 'access was denied'; } + // ERROR_SHARING_VIOLATION if (error.osError?.errorCode == 32) { return 'it was in use by another process'; } - if (error.osError?.errorCode == 145) { + // ERROR_DIR_NOT_EMPTY + if (!ignoreEmptyDir && _isDirectoryNotEmptyException(error)) { return 'of dart-lang/sdk#25353'; } return null; } - for (var i = 0; i < 2; i++) { + for (var i = 0; i < 3; i++) { try { operation(); - return; + break; } on FileSystemException catch (error) { var reason = getErrorReason(error); if (reason == null) rethrow; - log.io('Pub failed to $description because $reason. ' - 'Retrying in 50ms.'); - sleep(Duration(milliseconds: 50)); + if (i < 2) { + log.io('Pub failed to $description because $reason. ' + 'Retrying in 50ms.'); + sleep(Duration(milliseconds: 50)); + } else { + fail('Pub failed to $description because $reason.\n' + 'This may be caused by a virus scanner or having a file\n' + 'in the directory open in another application.'); + } } } - - try { - operation(); - } on FileSystemException catch (error) { - var reason = getErrorReason(error); - if (reason == null) rethrow; - - fail('Pub failed to $description because $reason.\n' - 'This may be caused by a virus scanner or having a file\n' - 'in the directory open in another application.'); - } } /// Deletes whatever's at [path], whether it's a file, directory, or symlink. @@ -448,14 +453,53 @@ void renameDir(String from, String to) { _attempt('rename directory', () { log.io('Renaming directory $from to $to.'); - try { - Directory(from).renameSync(to); - } on IOException { - // Ensure that [to] isn't left in an inconsistent state. See issue 12436. - if (entryExists(to)) deleteEntry(to); + Directory(from).renameSync(to); + }, ignoreEmptyDir: true); +} + +/// Renames directory [from] to [to]. +/// If it fails with "destination not empty" we log and continue, assuming +/// another process got there before us. +void tryRenameDir(String from, String to) { + ensureDir(path.dirname(to)); + try { + renameDir(from, to); + } on FileSystemException catch (e) { + tryDeleteEntry(from); + if (!_isDirectoryNotEmptyException(e)) { rethrow; } - }); + log.fine(''' +Destination directory $to already existed. +Assuming a concurrent pub invocation installed it.'''); + } +} + +void copyFile(String from, String to) { + log.io('Copying "$from" to "$to".'); + File(from).copySync(to); +} + +void renameFile(String from, String to) { + log.io('Renaming "$from" to "$to".'); + File(from).renameSync(to); +} + +bool _isDirectoryNotEmptyException(FileSystemException e) { + final errorCode = e.osError?.errorCode; + return + // On Linux rename will fail with ENOTEMPTY if directory exists: + // https://man7.org/linux/man-pages/man2/rename.2.html + // #define ENOTEMPTY 39 /* Directory not empty */ + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/errno.h#n20 + (Platform.isLinux && errorCode == 39) || + // On Windows this may fail with ERROR_DIR_NOT_EMPTY + // https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499- + (Platform.isWindows && errorCode == 145) || + // On MacOS rename will fail with ENOTEMPTY if directory exists. + // #define ENOTEMPTY 66 /* Directory not empty */ + // https://github.com/apple-oss-distributions/xnu/blob/bb611c8fecc755a0d8e56e2fa51513527c5b7a0e/bsd/sys/errno.h#L190 + (Platform.isMacOS && errorCode == 66); } /// Creates a new symlink at path [symlink] that points to [target]. @@ -557,10 +601,6 @@ return path.fromUri(url); })(); -/// A line-by-line stream of standard input. -final Stream<String> _stdinLines = - ByteStream(stdin).toStringStream().transform(const LineSplitter()); - /// Displays a message and reads a yes/no confirmation from the user. /// /// Returns a [Future] that completes to `true` if the user confirms or `false` @@ -576,7 +616,7 @@ } /// Writes [prompt] and reads a line from stdin. -Future<String> stdinPrompt(String prompt, {bool? echoMode}) { +Future<String> stdinPrompt(String prompt, {bool? echoMode}) async { if (runningFromTest) { log.message(prompt); } else { @@ -584,12 +624,16 @@ } if (echoMode != null && stdin.hasTerminal) { final previousEchoMode = stdin.echoMode; - stdin.echoMode = echoMode; - return _stdinLines.first.whenComplete(() { + try { + stdin.echoMode = echoMode; + final result = stdin.readLineSync() ?? ''; + stdout.write('\n'); + return result; + } finally { stdin.echoMode = previousEchoMode; - }); + } } else { - return _stdinLines.first; + return stdin.readLineSync() ?? ''; } } @@ -963,10 +1007,10 @@ log.fine(buffer.toString()); ArgumentError.checkNotNull(baseDir, 'baseDir'); - baseDir = path.absolute(baseDir); + baseDir = path.normalize(path.absolute(baseDir)); final tarContents = Stream.fromIterable(contents.map((entry) { - entry = path.absolute(entry); + entry = path.normalize(path.absolute(entry)); if (!path.isWithin(baseDir, entry)) { throw ArgumentError('Entry $entry is not inside $baseDir.'); } @@ -1023,22 +1067,16 @@ } /// The location for dart-specific configuration. -final String dartConfigDir = () { - // TODO: Migrate to new value from cli_util - if (runningFromTest) { +/// +/// `null` if no config dir could be found. +final String? dartConfigDir = () { + if (runningFromTest && + Platform.environment.containsKey('_PUB_TEST_CONFIG_DIR')) { return Platform.environment['_PUB_TEST_CONFIG_DIR']; } - String configDir; - if (Platform.isLinux) { - configDir = Platform.environment['XDG_CONFIG_HOME'] ?? - path.join(Platform.environment['HOME']!, '.config'); - } else if (Platform.isWindows) { - configDir = Platform.environment['APPDATA']!; - } else if (Platform.isMacOS) { - configDir = path.join( - Platform.environment['HOME']!, 'Library', 'Application Support'); - } else { - configDir = path.join(Platform.environment['HOME']!, '.config'); + try { + return applicationConfigHome('dart'); + } on EnvironmentNotFoundException { + return null; } - return path.join(configDir, 'dart'); -}()!; +}();
diff --git a/lib/src/language_version.dart b/lib/src/language_version.dart index e294014..ad331b2 100644 --- a/lib/src/language_version.dart +++ b/lib/src/language_version.dart
@@ -69,6 +69,21 @@ bool get supportsNullSafety => this >= firstVersionWithNullSafety; + /// Minimum language version at which short hosted syntax is supported. + /// + /// This allows `hosted` dependencies to be expressed as: + /// ```yaml + /// dependencies: + /// foo: + /// hosted: https://some-pub.com/path + /// version: ^1.0.0 + /// ``` + /// + /// At older versions, `hosted` dependencies had to be a map with a `url` and + /// a `name` key. + bool get supportsShorterHostedSyntax => + this >= firstVersionWithShorterHostedSyntax; + @override int compareTo(LanguageVersion other) { if (major != other.major) return major.compareTo(other.major); @@ -89,6 +104,7 @@ static const defaultLanguageVersion = LanguageVersion(2, 7); static const firstVersionWithNullSafety = LanguageVersion(2, 12); + static const firstVersionWithShorterHostedSyntax = LanguageVersion(2, 15); /// Transform language version to string that can be parsed with /// [LanguageVersion.parse].
diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart index b2139fe..8f563ab 100644 --- a/lib/src/lock_file.dart +++ b/lib/src/lock_file.dart
@@ -2,12 +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. -// @dart=2.10 - import 'dart:convert'; import 'package:collection/collection.dart' hide mapMap; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; @@ -52,10 +49,10 @@ /// `dependency_overrides` sections, respectively. These are consumed by the /// analysis server to provide better auto-completion. LockFile(Iterable<PackageId> ids, - {Map<String, VersionConstraint> sdkConstraints, - Set<String> mainDependencies, - Set<String> devDependencies, - Set<String> overriddenDependencies}) + {Map<String, VersionConstraint>? sdkConstraints, + Set<String>? mainDependencies, + Set<String>? devDependencies, + Set<String>? overriddenDependencies}) : this._( Map.fromIterable(ids.where((id) => !id.isRoot), key: (id) => id.name), @@ -94,10 +91,10 @@ /// [filePath] is the system-native path to the lockfile on disc. It may be /// `null`. static LockFile _parse( - String filePath, String contents, SourceRegistry sources) { + String? filePath, String contents, SourceRegistry sources) { if (contents.trim() == '') return LockFile.empty(); - Uri sourceUrl; + Uri? sourceUrl; if (filePath != null) sourceUrl = p.toUri(filePath); var parsed = loadYamlNode(contents, sourceUrl: sourceUrl); @@ -145,7 +142,7 @@ var description = spec['description']; // Let the source parse the description. - var source = sources[sourceName]; + var source = sources[sourceName]!; PackageId id; try { id = source.parseId(name, version, description, @@ -173,8 +170,6 @@ /// Asserts that [node] is a version constraint, and parses it. static VersionConstraint _parseVersionConstraint(YamlNode node) { - if (node == null) return null; - _validate(node.value is String, 'Invalid version constraint: must be a string.', node); @@ -199,9 +194,9 @@ } /// If [condition] is `false` throws a format error with [message] for [node]. - static void _validate(bool condition, String message, YamlNode node) { + static void _validate(bool condition, String message, YamlNode? node) { if (condition) return; - throw SourceSpanFormatException(message, node.span); + throw SourceSpanFormatException(message, node!.span); } /// Returns a copy of this LockFile with a package named [name] removed. @@ -222,8 +217,8 @@ /// directory. String packagesFile( SystemCache cache, { - String entrypoint, - @required String relativeFrom, + String? entrypoint, + String? relativeFrom, }) { var header = ''' This file is deprecated. Tools should instead consume @@ -233,9 +228,9 @@ Generated by pub on ${DateTime.now()}.'''; - var map = - Map<String, Uri>.fromIterable(ordered(packages.keys), value: (name) { - var id = packages[name]; + var map = Map<String, Uri>.fromIterable(ordered<String>(packages.keys), + value: (name) { + var id = packages[name]!; var source = cache.source(id.source); return p.toUri( p.join(source.getDirectory(id, relativeFrom: relativeFrom), 'lib')); @@ -259,13 +254,13 @@ /// current package has no SDK constraint. Future<String> packageConfigFile( SystemCache cache, { - String entrypoint, - VersionConstraint entrypointSdkConstraint, - @required String relativeFrom, + String? entrypoint, + VersionConstraint? entrypointSdkConstraint, + String? relativeFrom, }) async { final entries = <PackageConfigEntry>[]; for (final name in ordered(packages.keys)) { - final id = packages[name]; + final id = packages[name]!; final source = cache.source(id.source); final rootPath = source.getDirectory(id, relativeFrom: relativeFrom); Uri rootUri; @@ -311,17 +306,18 @@ /// Returns the serialized YAML text of the lock file. /// /// [packageDir] is the containing directory of the root package, used to - /// properly serialize package descriptions. - String serialize(String packageDir) { + /// serialize relative path package descriptions. If it is null, they will be + /// serialized as absolute. + String serialize(String? packageDir) { // Convert the dependencies to a simple object. var packageMap = {}; packages.forEach((name, package) { var description = - package.source.serializeDescription(packageDir, package.description); + package.source!.serializeDescription(packageDir, package.description); packageMap[name] = { 'version': package.version.toString(), - 'source': package.source.name, + 'source': package.source!.name, 'description': description, 'dependency': _dependencyType(package.name) };
diff --git a/lib/src/log.dart b/lib/src/log.dart index ff7fe29..db24d7a 100644 --- a/lib/src/log.dart +++ b/lib/src/log.dart
@@ -12,9 +12,11 @@ import 'package:source_span/source_span.dart'; import 'package:stack_trace/stack_trace.dart'; +import 'entrypoint.dart'; import 'exceptions.dart'; import 'io.dart'; import 'progress.dart'; +import 'sdk.dart'; import 'transcript.dart'; import 'utils.dart'; @@ -24,7 +26,7 @@ final json = _JsonLogger(); /// The current logging verbosity. -Verbosity verbosity = Verbosity.NORMAL; +Verbosity verbosity = Verbosity.normal; /// In cases where there's a ton of log spew, make sure we don't eat infinite /// memory. @@ -32,11 +34,11 @@ /// This can occur when the backtracking solver stumbles into a pathological /// dependency graph. It generally will find a solution, but it may log /// thousands and thousands of entries to get there. -const _MAX_TRANSCRIPT = 10000; +const _maxTranscript = 10000; /// The list of recorded log messages. Will only be recorded if /// [recordTranscript()] is called. -Transcript<_Entry>? _transcript; +final Transcript<_Entry> _transcript = Transcript(_maxTranscript); /// The currently-animated progress indicator, if any. /// @@ -58,34 +60,34 @@ /// An enum type for defining the different logging levels a given message can /// be associated with. /// -/// By default, [ERROR] and [WARNING] messages are printed to sterr. [MESSAGE] +/// By default, [error] and [warning] messages are printed to sterr. [message] /// messages are printed to stdout, and others are ignored. class Level { /// An error occurred and an operation could not be completed. /// /// Usually shown to the user on stderr. - static const ERROR = Level._('ERR '); + static const error = Level._('ERR '); /// Something unexpected happened, but the program was able to continue, /// though possibly in a degraded fashion. - static const WARNING = Level._('WARN'); + static const warning = Level._('WARN'); /// A message intended specifically to be shown to the user. - static const MESSAGE = Level._('MSG '); + static const message = Level._('MSG '); /// Some interaction with the external world occurred, such as a network /// operation, process spawning, or file IO. - static const IO = Level._('IO '); + static const io = Level._('IO '); /// Incremental output during pub's version constraint solver. - static const SOLVER = Level._('SLVR'); + static const solver = Level._('SLVR'); /// Fine-grained and verbose additional information. /// /// Used to provide program state context for other logs (such as what pub /// was doing when an IO operation occurred) or just more detail for an /// operation. - static const FINE = Level._('FINE'); + static const fine = Level._('FINE'); const Level._(this.name); @@ -99,73 +101,83 @@ /// displayed. class Verbosity { /// Silence all logging. - static const NONE = Verbosity._('none', { - Level.ERROR: null, - Level.WARNING: null, - Level.MESSAGE: null, - Level.IO: null, - Level.SOLVER: null, - Level.FINE: null + static const none = Verbosity._('none', { + Level.error: null, + Level.warning: null, + Level.message: null, + Level.io: null, + Level.solver: null, + Level.fine: null }); /// Shows only errors. - static const ERROR = Verbosity._('error', { - Level.ERROR: _logToStderr, - Level.WARNING: null, - Level.MESSAGE: null, - Level.IO: null, - Level.SOLVER: null, - Level.FINE: null + static const error = Verbosity._('error', { + Level.error: _logToStderr, + Level.warning: null, + Level.message: null, + Level.io: null, + Level.solver: null, + Level.fine: null }); /// Shows only errors and warnings. - static const WARNING = Verbosity._('warning', { - Level.ERROR: _logToStderr, - Level.WARNING: _logToStderr, - Level.MESSAGE: null, - Level.IO: null, - Level.SOLVER: null, - Level.FINE: null + static const warning = Verbosity._('warning', { + Level.error: _logToStderr, + Level.warning: _logToStderr, + Level.message: null, + Level.io: null, + Level.solver: null, + Level.fine: null }); /// The default verbosity which shows errors, warnings, and messages. - static const NORMAL = Verbosity._('normal', { - Level.ERROR: _logToStderr, - Level.WARNING: _logToStderr, - Level.MESSAGE: _logToStdout, - Level.IO: null, - Level.SOLVER: null, - Level.FINE: null + static const normal = Verbosity._('normal', { + Level.error: _logToStderr, + Level.warning: _logToStderr, + Level.message: _logToStdout, + Level.io: null, + Level.solver: null, + Level.fine: null }); /// Shows errors, warnings, messages, and IO event logs. - static const IO = Verbosity._('io', { - Level.ERROR: _logToStderrWithLabel, - Level.WARNING: _logToStderrWithLabel, - Level.MESSAGE: _logToStdoutWithLabel, - Level.IO: _logToStderrWithLabel, - Level.SOLVER: null, - Level.FINE: null + static const io = Verbosity._('io', { + Level.error: _logToStderrWithLabel, + Level.warning: _logToStderrWithLabel, + Level.message: _logToStdoutWithLabel, + Level.io: _logToStderrWithLabel, + Level.solver: null, + Level.fine: null }); /// Shows errors, warnings, messages, and version solver logs. - static const SOLVER = Verbosity._('solver', { - Level.ERROR: _logToStderr, - Level.WARNING: _logToStderr, - Level.MESSAGE: _logToStdout, - Level.IO: null, - Level.SOLVER: _logToStdout, - Level.FINE: null + static const solver = Verbosity._('solver', { + Level.error: _logToStderr, + Level.warning: _logToStderr, + Level.message: _logToStdout, + Level.io: null, + Level.solver: _logToStdout, + Level.fine: null }); /// Shows all logs. - static const ALL = Verbosity._('all', { - Level.ERROR: _logToStderrWithLabel, - Level.WARNING: _logToStderrWithLabel, - Level.MESSAGE: _logToStdoutWithLabel, - Level.IO: _logToStderrWithLabel, - Level.SOLVER: _logToStderrWithLabel, - Level.FINE: _logToStderrWithLabel + static const all = Verbosity._('all', { + Level.error: _logToStderrWithLabel, + Level.warning: _logToStderrWithLabel, + Level.message: _logToStdoutWithLabel, + Level.io: _logToStderrWithLabel, + Level.solver: _logToStderrWithLabel, + Level.fine: _logToStderrWithLabel + }); + + /// Shows all logs. + static const testing = Verbosity._('testing', { + Level.error: _logToStderrWithLabel, + Level.warning: _logToStderrWithLabel, + Level.message: _logToStdoutWithLabel, + Level.io: _logToStderrWithLabel, + Level.solver: _logToStderrWithLabel, + Level.fine: _logToStderrWithLabel }); const Verbosity._(this.name, this._loggers); @@ -188,7 +200,7 @@ _Entry(this.level, this.lines); } -/// Logs [message] at [Level.ERROR]. +/// Logs [message] at [Level.error]. /// /// If [error] is passed, it's appended to [message]. If [trace] is passed, it's /// printed at log level fine. @@ -198,24 +210,24 @@ message = message.isEmpty ? '$error' : '$message: $error'; if (error is Error && trace == null) trace = error.stackTrace; } - write(Level.ERROR, message); - if (trace != null) write(Level.FINE, Chain.forTrace(trace)); + write(Level.error, message); + if (trace != null) write(Level.fine, Chain.forTrace(trace)); } -/// Logs [message] at [Level.WARNING]. -void warning(message) => write(Level.WARNING, message); +/// Logs [message] at [Level.warning]. +void warning(message) => write(Level.warning, message); -/// Logs [message] at [Level.MESSAGE]. -void message(message) => write(Level.MESSAGE, message); +/// Logs [message] at [Level.message]. +void message(message) => write(Level.message, message); -/// Logs [message] at [Level.IO]. -void io(message) => write(Level.IO, message); +/// Logs [message] at [Level.io]. +void io(message) => write(Level.io, message); -/// Logs [message] at [Level.SOLVER]. -void solver(message) => write(Level.SOLVER, message); +/// Logs [message] at [Level.solver]. +void solver(message) => write(Level.solver, message); -/// Logs [message] at [Level.FINE]. -void fine(message) => write(Level.FINE, message); +/// Logs [message] at [Level.fine]. +void fine(message) => write(Level.fine, message); /// Logs [message] at [level]. void write(Level level, message) { @@ -233,10 +245,10 @@ var logFn = verbosity._loggers[level]; if (logFn != null) logFn(entry); - if (_transcript != null) _transcript!.add(entry); + _transcript.add(entry); } -/// Logs the spawning of an [executable] process with [arguments] at [IO] +/// Logs the spawning of an [executable] process with [arguments] at [io] /// level. void process( String executable, List<String> arguments, String workingDirectory) { @@ -313,18 +325,10 @@ } } -/// Enables recording of log entries. -void recordTranscript() { - _transcript = Transcript<_Entry>(_MAX_TRANSCRIPT); -} - -/// If [recordTranscript()] was called, then prints the previously recorded log -/// transcript to stderr. -void dumpTranscript() { - if (_transcript == null) return; - +/// Prints the recorded log transcript to stderr. +void dumpTranscriptToStdErr() { stderr.writeln('---- Log transcript ----'); - _transcript!.forEach((entry) { + _transcript.forEach((entry) { _printToStream(stderr, entry, showLabel: true); }, (discarded) { stderr.writeln('---- ($discarded discarded) ----'); @@ -332,6 +336,68 @@ stderr.writeln('---- End log transcript ----'); } +String _limit(String input, int limit) { + const snip = '[...]'; + if (input.length < limit - snip.length) return input; + return '${input.substring(0, limit ~/ 2 - snip.length)}' + '$snip' + '${input.substring(limit)}'; +} + +/// Prints relevant system information and the log transcript to [path]. +void dumpTranscriptToFile(String path, String command, Entrypoint? entrypoint) { + final buffer = StringBuffer(); + buffer.writeln(''' +Information about the latest pub run. + +If you believe something is not working right, you can go to +https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file. + +Before making this file public, make sure to remove any sensitive information! + +Pub version: ${sdk.version} +Created: ${DateTime.now().toIso8601String()} +FLUTTER_ROOT: ${Platform.environment['FLUTTER_ROOT'] ?? '<not set>'} +PUB_HOSTED_URL: ${Platform.environment['PUB_HOSTED_URL'] ?? '<not set>'} +PUB_CACHE: "${Platform.environment['PUB_CACHE'] ?? '<not set>'}" +Command: $command +Platform: ${Platform.operatingSystem} +'''); + + if (entrypoint != null) { + buffer.writeln('---- ${p.absolute(entrypoint.pubspecPath)} ----'); + if (fileExists(entrypoint.pubspecPath)) { + buffer.writeln(_limit(readTextFile(entrypoint.pubspecPath), 5000)); + } else { + buffer.writeln('<No pubspec.yaml>'); + } + buffer.writeln('---- End pubspec.yaml ----'); + buffer.writeln('---- ${p.absolute(entrypoint.lockFilePath)} ----'); + if (fileExists(entrypoint.lockFilePath)) { + buffer.writeln(_limit(readTextFile(entrypoint.lockFilePath), 5000)); + } else { + buffer.writeln('<No pubspec.lock>'); + } + buffer.writeln('---- End pubspec.lock ----'); + } + + buffer.writeln('---- Log transcript ----'); + + _transcript.forEach((entry) { + _printToStream(buffer, entry, showLabel: true); + }, (discarded) { + buffer.writeln('---- ($discarded entries discarded) ----'); + }); + buffer.writeln('---- End log transcript ----'); + ensureDir(p.dirname(path)); + try { + writeTextFile(path, buffer.toString(), dontLogContents: true); + } on IOException catch (e) { + stderr.writeln('Failed writing log to `$path` ($e), writing it to stderr:'); + dumpTranscriptToStdErr(); + } +} + /// Filter out normal pub output when not attached to a terminal /// /// Unless the user has overriden the verbosity, @@ -339,8 +405,8 @@ /// This is useful to not pollute stdout when the output is piped somewhere. Future<T> warningsOnlyUnlessTerminal<T>(FutureOr<T> Function() callback) async { final oldVerbosity = verbosity; - if (verbosity == Verbosity.NORMAL && !stdout.hasTerminal) { - verbosity = Verbosity.WARNING; + if (verbosity == Verbosity.normal && !stdout.hasTerminal) { + verbosity = Verbosity.warning; } final result = await callback(); verbosity = oldVerbosity; @@ -353,7 +419,7 @@ /// If anything else is logged during this (including another call to /// [progress]) that cancels the progress animation, although the total time /// will still be printed once it finishes. If [fine] is passed, the progress -/// information will only be visible at [Level.FINE]. +/// information will only be visible at [Level.fine]. Future<T> progress<T>(String message, Future<T> Function() callback) { _stopProgress(); @@ -492,7 +558,7 @@ _printToStream(sink, entry, showLabel: showLabel); } -void _printToStream(IOSink sink, _Entry entry, {required bool showLabel}) { +void _printToStream(StringSink sink, _Entry entry, {required bool showLabel}) { _stopProgress(); var firstLine = true;
diff --git a/lib/src/null_safety_analysis.dart b/lib/src/null_safety_analysis.dart index fb1c8ad..5b882a8 100644 --- a/lib/src/null_safety_analysis.dart +++ b/lib/src/null_safety_analysis.dart
@@ -2,13 +2,11 @@ // 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. -// @dart=2.10 - import 'dart:async'; -import 'package:analyzer/dart/analysis/context_builder.dart'; -import 'package:analyzer/dart/analysis/context_locator.dart'; +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/dart/analysis/results.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:cli_util/cli_util.dart'; import 'package:path/path.dart' as path; import 'package:source_span/source_span.dart'; @@ -74,16 +72,17 @@ /// If [packageId] is a relative path dependency [containingPath] must be /// provided with an absolute path to resolve it against. Future<NullSafetyAnalysisResult> nullSafetyCompliance(PackageId packageId, - {String containingPath}) async { + {String? containingPath}) async { // A space in the name prevents clashes with other package names. final fakeRootName = '${packageId.name} importer'; final fakeRoot = Package.inMemory(Pubspec(fakeRootName, fields: { 'dependencies': { packageId.name: { - packageId.source.name: packageId.source is PathSource + packageId.source!.name: packageId.source is PathSource ? (packageId.description['relative'] - ? path.join(containingPath, packageId.description['path']) + ? path.join( + containingPath!, packageId.description['path']) : packageId.description['path']) : packageId.description, 'version': packageId.version.toString(), @@ -93,7 +92,7 @@ sources: _systemCache.sources)); final rootPubspec = - await packageId.source.bind(_systemCache).describe(packageId); + await packageId.source!.bind(_systemCache).describe(packageId); final rootLanguageVersion = rootPubspec.languageVersion; if (!rootLanguageVersion.supportsNullSafety) { final span = @@ -110,7 +109,7 @@ SolveResult result; try { result = await resolveVersions( - SolveType.GET, + SolveType.get, _systemCache, fakeRoot, ); @@ -119,10 +118,10 @@ 'Could not resolve constraints: $e'); } return nullSafetyComplianceOfPackages( - result.packages.where((id) => id.name != fakeRootName), - Package(rootPubspec, - packageId.source.bind(_systemCache).getDirectory(packageId)), - containingPath); + result.packages.where((id) => id.name != fakeRootName), + Package(rootPubspec, + packageId.source!.bind(_systemCache).getDirectory(packageId)), + ); } /// Decides if all dependendencies (transitively) have a language version @@ -139,14 +138,13 @@ Future<NullSafetyAnalysisResult> nullSafetyComplianceOfPackages( Iterable<PackageId> packages, Package rootPackage, - String containingPath, ) async { - NullSafetyAnalysisResult firstBadPackage; + NullSafetyAnalysisResult? firstBadPackage; for (final dependencyId in packages) { final packageInternalAnalysis = await _packageInternallyGoodCache.putIfAbsent(dependencyId, () async { Pubspec pubspec; - BoundSource boundSource; + BoundSource? boundSource; String packageDir; if (dependencyId.source == null) { pubspec = rootPackage.pubspec; @@ -177,14 +175,13 @@ final libDir = path.absolute(path.normalize(path.join(packageDir, 'lib'))); if (dirExists(libDir)) { - final analysisSession = ContextBuilder() - .createContext( - sdkPath: getSdkPath(), - contextRoot: ContextLocator().locateRoots( - includedPaths: [path.normalize(packageDir)], - ).first, - ) - .currentSession; + var contextCollection = AnalysisContextCollection( + includedPaths: [path.normalize(packageDir)], + resourceProvider: PhysicalResourceProvider.INSTANCE, + sdkPath: getSdkPath(), + ); + var analysisContext = contextCollection.contexts.first; + var analysisSession = analysisContext.currentSession; for (final file in listDir(libDir, recursive: true, includeDirs: false, includeHidden: true)) { @@ -192,7 +189,7 @@ final fileUrl = 'package:${dependencyId.name}/${path.relative(file, from: libDir)}'; final someUnitResult = - analysisSession.getParsedUnit2(path.normalize(file)); + analysisSession.getParsedUnit(path.normalize(file)); ParsedUnitResult unitResult; if (someUnitResult is ParsedUnitResult) { unitResult = someUnitResult; @@ -225,7 +222,6 @@ } return NullSafetyAnalysisResult(NullSafetyCompliance.compliant, null); }); - assert(packageInternalAnalysis != null); if (packageInternalAnalysis.compliance == NullSafetyCompliance.analysisFailed) { return packageInternalAnalysis; @@ -251,12 +247,12 @@ final NullSafetyCompliance compliance; /// `null` if compliance == [NullSafetyCompliance.compliant]. - final String reason; + final String? reason; NullSafetyAnalysisResult(this.compliance, this.reason); } -SourceSpan _tryGetSpanFromYamlMap(Object map, String key) { +SourceSpan? _tryGetSpanFromYamlMap(Object? map, String key) { if (map is YamlMap) { return map.nodes[key]?.span; }
diff --git a/lib/src/oauth2.dart b/lib/src/oauth2.dart index c1284e9..7229bb1 100644 --- a/lib/src/oauth2.dart +++ b/lib/src/oauth2.dart
@@ -2,11 +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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:oauth2/oauth2.dart'; import 'package:path/path.dart' as path; import 'package:shelf/shelf.dart' as shelf; @@ -64,19 +63,21 @@ /// /// This should always be the same as the credentials file stored in the system /// cache. -Credentials _credentials; +Credentials? _credentials; /// Delete the cached credentials, if they exist. void _clearCredentials(SystemCache cache) { _credentials = null; var credentialsFile = _credentialsFile(cache); - if (entryExists(credentialsFile)) deleteEntry(credentialsFile); + if (credentialsFile != null && entryExists(credentialsFile)) { + deleteEntry(credentialsFile); + } } /// Try to delete the cached credentials. void logout(SystemCache cache) { var credentialsFile = _credentialsFile(cache); - if (entryExists(_credentialsFile(cache))) { + if (credentialsFile != null && entryExists(credentialsFile)) { log.message('Logging out of pub.dartlang.org.'); log.message('Deleting $credentialsFile'); _clearCredentials(cache); @@ -151,14 +152,14 @@ /// /// If the credentials can't be loaded for any reason, the returned [Future] /// completes to `null`. -Credentials loadCredentials(SystemCache cache) { +Credentials? loadCredentials(SystemCache cache) { log.fine('Loading OAuth2 credentials.'); try { if (_credentials != null) return _credentials; var path = _credentialsFile(cache); - if (!fileExists(path)) return null; + if (path == null || !fileExists(path)) return null; var credentials = Credentials.fromJson(readTextFile(path)); if (credentials.isExpired && !credentials.canRefresh) { @@ -181,8 +182,10 @@ log.fine('Saving OAuth2 credentials.'); _credentials = credentials; var credentialsPath = _credentialsFile(cache); - ensureDir(path.dirname(credentialsPath)); - writeTextFile(credentialsPath, credentials.toJson(), dontLogContents: true); + if (credentialsPath != null) { + ensureDir(path.dirname(credentialsPath)); + writeTextFile(credentialsPath, credentials.toJson(), dontLogContents: true); + } } /// The path to the file in which the user's OAuth2 credentials are stored. @@ -191,10 +194,18 @@ /// best place for storing secrets, as it might be shared. /// /// To provide backwards compatibility we use the legacy file if only it exists. -String _credentialsFile(SystemCache cache) { - final newCredentialsFile = path.join(dartConfigDir, 'pub-credentials.json'); - return [newCredentialsFile, _legacyCredentialsFile(cache)] - .firstWhere(fileExists, orElse: () => newCredentialsFile); +/// +/// Returns `null` if there is no good place for the file. +String? _credentialsFile(SystemCache cache) { + final configDir = dartConfigDir; + + final newCredentialsFile = + configDir == null ? null : path.join(configDir, 'pub-credentials.json'); + var file = [ + if (newCredentialsFile != null) newCredentialsFile, + _legacyCredentialsFile(cache) + ].firstWhereOrNull(fileExists); + return file ?? newCredentialsFile; } String _legacyCredentialsFile(SystemCache cache) { @@ -223,7 +234,7 @@ } log.message('Authorization received, processing...'); - var queryString = request.url.query ?? ''; + var queryString = request.url.query; // Closing the server here is safe, since it will wait until the response // is sent to actually shut down. server.close();
diff --git a/lib/src/package.dart b/lib/src/package.dart index 6a3b0ff..d100157 100644 --- a/lib/src/package.dart +++ b/lib/src/package.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. -// @dart=2.10 - import 'dart:io'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; @@ -36,19 +35,26 @@ return a.version.compareTo(b.version); } + final String? _dir; + /// The path to the directory containing the package. - final String dir; + /// + /// It is an error to access this on an in-memory package. + String get dir { + if (isInMemory) { + throw UnsupportedError( + 'Package directory cannot be used for an in-memory package'); + } + + return _dir!; + } /// An in-memory package can be created for doing a resolution without having /// a package on disk. Paths should not be resolved for these. - bool get _isInMemory => dir == null; + bool get isInMemory => _dir == null; /// The name of the package. - String get name { - if (pubspec.name != null) return pubspec.name; - if (dir != null) return p.basename(dir); - return null; - } + String get name => pubspec.name; /// The package's version. Version get version => pubspec.version; @@ -77,10 +83,12 @@ ..addAll(dependencyOverrides); } - /// Returns a list of asset ids for all Dart executables in this package's bin + /// Returns a list of paths to all Dart executables in this package's bin /// directory. List<String> get executablePaths { - return ordered(listFiles(beneath: 'bin', recursive: false)) + final binDir = p.join(dir, 'bin'); + if (!dirExists(binDir)) return <String>[]; + return ordered(listDir(p.join(dir, 'bin'), includeDirs: false)) .where((executable) => p.extension(executable) == '.dart') .map((executable) => p.relative(executable, from: dir)) .toList(); @@ -95,7 +103,7 @@ /// If multiple READMEs are found, this uses the same conventions as /// pub.dartlang.org for choosing the primary one: the README with the fewest /// extensions that is lexically ordered first is chosen. - String get readmePath { + String? get readmePath { var readmes = listFiles(recursive: false) .map(p.basename) .where((entry) => entry.contains(_readmeRegexp)); @@ -112,61 +120,57 @@ /// Returns the path to the CHANGELOG file at the root of the entrypoint, or /// null if no CHANGELOG file is found. - String get changelogPath { - return listFiles(recursive: false).firstWhere( - (entry) => p.basename(entry).contains(_changelogRegexp), - orElse: () => null); + String? get changelogPath { + return listFiles(recursive: false).firstWhereOrNull( + (entry) => p.basename(entry).contains(_changelogRegexp)); } /// Returns whether or not this package is in a Git repo. - bool get inGitRepo { - if (_inGitRepoCache != null) return _inGitRepoCache; + late final bool inGitRepo = computeInGitRepoCache(); - if (dir == null || !git.isInstalled) { - _inGitRepoCache = false; + bool computeInGitRepoCache() { + if (isInMemory || !git.isInstalled) { + return false; } else { // If the entire package directory is ignored, don't consider it part of a // git repo. `git check-ignore` will return a status code of 0 for // ignored, 1 for not ignored, and 128 for not a Git repo. - var result = runProcessSync(git.command, ['check-ignore', '--quiet', '.'], + var result = runProcessSync( + git.command!, ['check-ignore', '--quiet', '.'], workingDir: dir); - _inGitRepoCache = result.exitCode == 1; + return result.exitCode == 1; } - - return _inGitRepoCache; } - bool _inGitRepoCache; - /// Loads the package whose root directory is [packageDir]. /// /// [name] is the expected name of that package (e.g. the name given in the /// dependency), or `null` if the package being loaded is the entrypoint /// package. - Package.load(String name, this.dir, SourceRegistry sources) - : pubspec = Pubspec.load(dir, sources, expectedName: name); + Package.load(String? name, String this._dir, SourceRegistry sources) + : pubspec = Pubspec.load(_dir, sources, expectedName: name); /// Constructs a package with the given pubspec. /// /// The package will have no directory associated with it. - Package.inMemory(this.pubspec) : dir = null; + Package.inMemory(this.pubspec) : _dir = null; /// Creates a package with [pubspec] located at [dir]. - Package(this.pubspec, this.dir); + Package(this.pubspec, String this._dir); /// Given a relative path within this package, returns its absolute path. /// /// This is similar to `p.join(dir, part1, ...)`, except that subclasses may /// override it to report that certain paths exist elsewhere than within /// [dir]. - String path(String part1, - [String part2, - String part3, - String part4, - String part5, - String part6, - String part7]) { - if (_isInMemory) { + String path(String? part1, + [String? part2, + String? part3, + String? part4, + String? part5, + String? part6, + String? part7]) { + if (isInMemory) { throw StateError("Package $name is in-memory and doesn't have paths " 'on disk.'); } @@ -176,7 +180,7 @@ /// Given an absolute path within this package (such as that returned by /// [path] or [listFiles]), returns it relative to the package root. String relative(String path) { - if (dir == null) { + if (isInMemory) { throw StateError("Package $name is in-memory and doesn't have paths " 'on disk.'); } @@ -184,7 +188,7 @@ } /// Returns the type of dependency from this package onto [name]. - DependencyType dependencyType(String name) { + DependencyType dependencyType(String? name) { if (pubspec.fields['dependencies']?.containsKey(name) ?? false) { return DependencyType.direct; } else if (pubspec.fields['dev_dependencies']?.containsKey(name) ?? false) { @@ -220,22 +224,15 @@ /// /// Note that the returned paths won't always be beneath [dir]. To safely /// convert them to paths relative to the package root, use [relative]. - List<String> listFiles({String beneath, bool recursive = true}) { + List<String> listFiles({String? beneath, bool recursive = true}) { // An in-memory package has no files. - if (dir == null) return []; + if (isInMemory) return []; - var root = dir; - if (git.isInstalled) { - try { - root = p.normalize( - git.runSync(['rev-parse', '--show-toplevel'], workingDir: dir).first, - ); - } on git.GitException { - // Not in a git folder. - } - } + var packageDir = dir; + var root = git.repoRoot(packageDir) ?? packageDir; beneath = p - .toUri(p.normalize(p.relative(p.join(dir, beneath ?? '.'), from: root))) + .toUri(p.normalize( + p.relative(p.join(packageDir, beneath ?? '.'), from: root))) .path; if (beneath == './') beneath = '.'; String resolve(String path) { @@ -279,7 +276,7 @@ : (fileExists(gitIgnore) ? gitIgnore : null); final rules = [ - if (dir == '.') ..._basicIgnoreRules, + if (dir == beneath) ..._basicIgnoreRules, if (ignoreFile != null) readTextFile(ignoreFile), ]; return rules.isEmpty
diff --git a/lib/src/package_config.dart b/lib/src/package_config.dart index fad20f7..d64808b 100644 --- a/lib/src/package_config.dart +++ b/lib/src/package_config.dart
@@ -2,9 +2,7 @@ // 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. -// @dart=2.10 - -import 'package:meta/meta.dart'; +import 'dart:convert'; import 'package:pub_semver/pub_semver.dart'; @@ -22,38 +20,36 @@ /// Date-time the `.dart_tool/package_config.json` file was generated. /// - /// This property is **optional** and may be `null` if not given. - DateTime generated; + /// `null` if not given. + DateTime? generated; /// Tool that generated the `.dart_tool/package_config.json` file. /// /// For `pub` this is always `'pub'`. /// - /// This property is **optional** and may be `null` if not given. - String generator; + /// `null` if not given. + String? generator; /// Version of the tool that generated the `.dart_tool/package_config.json` /// file. /// /// For `pub` this is the Dart SDK version from which `pub get` was called. /// - /// This property is **optional** and may be `null` if not given. - Version generatorVersion; + /// `null` if not given. + Version? generatorVersion; /// Additional properties not in the specification for the /// `.dart_tool/package_config.json` file. Map<String, dynamic> additionalProperties; PackageConfig({ - @required this.configVersion, - @required this.packages, + required this.configVersion, + required this.packages, this.generated, this.generator, this.generatorVersion, - this.additionalProperties, - }) { - additionalProperties ??= {}; - } + Map<String, dynamic>? additionalProperties, + }) : additionalProperties = additionalProperties ?? {}; /// Create [PackageConfig] from JSON [data]. /// @@ -63,7 +59,7 @@ if (data is! Map<String, dynamic>) { throw FormatException('package_config.json must be a JSON object'); } - final root = data as Map<String, dynamic>; + final root = data; void _throw(String property, String mustBe) => throw FormatException( '"$property" in .dart_tool/package_config.json $mustBe'); @@ -87,7 +83,7 @@ } // Read the 'generated' property - DateTime generated; + DateTime? generated; final generatedRaw = root['generated']; if (generatedRaw != null) { if (generatedRaw is! String) { @@ -104,7 +100,7 @@ } // Read the 'generatorVersion' property - Version generatorVersion; + Version? generatorVersion; final generatorVersionRaw = root['generatorVersion']; if (generatorVersionRaw != null) { if (generatorVersionRaw is! String) { @@ -134,13 +130,13 @@ } /// Convert to JSON structure. - Map<String, Object> toJson() => { + Map<String, Object?> toJson() => { 'configVersion': configVersion, 'packages': packages.map((p) => p.toJson()).toList(), - 'generated': generated?.toUtc()?.toIso8601String(), + 'generated': generated?.toUtc().toIso8601String(), 'generator': generator, 'generatorVersion': generatorVersion?.toString(), - }..addAll(additionalProperties ?? {}); + }..addAll(additionalProperties); } class PackageConfigEntry { @@ -158,31 +154,27 @@ /// Import statements in Dart programs are resolved relative to this folder. /// This must be in the sub-tree under [rootUri]. /// - /// This property is **optional** and may be `null` if not given. - Uri packageUri; + /// `null` if not given. + Uri? packageUri; /// Language version used by package. /// /// Given as `<major>.<minor>` version, similar to the `// @dart = X.Y` /// comment. This is derived from the lower-bound on the Dart SDK requirement /// in the `pubspec.yaml` for the given package. - /// - /// This property is **optional** and may be `null` if not given. - LanguageVersion languageVersion; + LanguageVersion? languageVersion; /// Additional properties not in the specification for the /// `.dart_tool/package_config.json` file. - Map<String, dynamic> additionalProperties; + Map<String, dynamic>? additionalProperties; PackageConfigEntry({ - @required this.name, - @required this.rootUri, + required this.name, + required this.rootUri, this.packageUri, this.languageVersion, - this.additionalProperties, - }) { - additionalProperties ??= {}; - } + this.additionalProperties = const {}, + }); /// Create [PackageConfigEntry] from JSON [data]. /// @@ -193,9 +185,9 @@ throw FormatException( 'packages[] entries in package_config.json must be JSON objects'); } - final root = data as Map<String, dynamic>; + final root = data; - void _throw(String property, String mustBe) => throw FormatException( + Never _throw(String property, String mustBe) => throw FormatException( '"packages[].$property" in .dart_tool/package_config.json $mustBe'); final name = root['name']; @@ -203,7 +195,7 @@ _throw('name', 'must be a string'); } - Uri rootUri; + final Uri rootUri; final rootUriRaw = root['rootUri']; if (rootUriRaw is! String) { _throw('rootUri', 'must be a string'); @@ -214,7 +206,7 @@ _throw('rootUri', 'must be a URI'); } - Uri packageUri; + Uri? packageUri; var packageUriRaw = root['packageUri']; if (packageUriRaw != null) { if (packageUriRaw is! String) { @@ -230,7 +222,7 @@ } } - LanguageVersion languageVersion; + LanguageVersion? languageVersion; final languageVersionRaw = root['languageVersion']; if (languageVersionRaw != null) { if (languageVersionRaw is! String) { @@ -252,10 +244,16 @@ } /// Convert to JSON structure. - Map<String, Object> toJson() => { + Map<String, Object?> toJson() => { 'name': name, 'rootUri': rootUri.toString(), - if (packageUri != null) 'packageUri': packageUri?.toString(), + if (packageUri != null) 'packageUri': packageUri.toString(), if (languageVersion != null) 'languageVersion': '$languageVersion', }..addAll(additionalProperties ?? {}); + + @override + String toString() { + // TODO: implement toString + return JsonEncoder.withIndent(' ').convert(toJson()); + } }
diff --git a/lib/src/package_graph.dart b/lib/src/package_graph.dart index ed1f30f..45351d7 100644 --- a/lib/src/package_graph.dart +++ b/lib/src/package_graph.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:collection/collection.dart' hide mapMap; import 'entrypoint.dart'; @@ -32,7 +30,7 @@ final Map<String, Package> packages; /// A map of transitive dependencies for each package. - Map<String, Set<Package>> _transitiveDependencies; + Map<String, Set<Package>>? _transitiveDependencies; PackageGraph(this.entrypoint, this.lockFile, this.packages); @@ -47,7 +45,7 @@ value: (id) { if (id.name == entrypoint.root.name) return entrypoint.root; - return Package(result.pubspecs[id.name], + return Package(result.pubspecs[id.name]!, entrypoint.cache.source(id.source).getDirectory(id)); }); @@ -69,13 +67,12 @@ _transitiveDependencies = mapMap<String, Set<String>, String, Set<Package>>(closure, value: (depender, names) { - var set = names.map((name) => packages[name]).toSet(); - set.add(packages[depender]); + var set = names.map((name) => packages[name]!).toSet(); + set.add(packages[depender]!); return set; }); } - - return _transitiveDependencies[package]; + return _transitiveDependencies![package]!; } bool _isPackageCached(String package) { @@ -86,7 +83,7 @@ if (package == entrypoint.root.name) { return entrypoint.isCached; } else { - var id = lockFile.packages[package]; + var id = lockFile.packages[package]!; return entrypoint.cache.source(id.source) is CachedSource; } }
diff --git a/lib/src/package_name.dart b/lib/src/package_name.dart index a301338..d83f466 100644 --- a/lib/src/package_name.dart +++ b/lib/src/package_name.dart
@@ -2,16 +2,12 @@ // 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. -// @dart=2.10 - import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package.dart'; import 'source.dart'; -import 'source/git.dart'; import 'source/hosted.dart'; -import 'source/path.dart'; import 'utils.dart'; /// The equality to use when comparing the feature sets of two package names. @@ -25,7 +21,7 @@ /// The [Source] used to look up this package. /// /// If this is a root package, this will be `null`. - final Source source; + final Source? source; /// The metadata used by the package's [source] to identify and locate it. /// @@ -53,25 +49,31 @@ /// `this.toRef() == other.toRef()`. bool samePackage(PackageName other) { if (other.name != name) return false; - if (source == null) return other.source == null; + var thisSource = source; + if (thisSource == null) return other.source == null; - return other.source == source && - source.descriptionsEqual(description, other.description); + return other.source == thisSource && + thisSource.descriptionsEqual(description, other.description); } @override + bool operator ==(Object other) => + throw UnimplementedError('Subclass should implement =='); + + @override int get hashCode { - if (source == null) return name.hashCode; + var thisSource = source; + if (thisSource == null) return name.hashCode; return name.hashCode ^ - source.hashCode ^ - source.hashDescription(description); + thisSource.hashCode ^ + thisSource.hashDescription(description); } /// Returns a string representation of this package name. /// /// If [detail] is passed, it controls exactly which details are included. @override - String toString([PackageDetail detail]); + String toString([PackageDetail? detail]); } /// A reference to a [Package], but not any particular version(s) of it. @@ -82,14 +84,14 @@ /// Since an ID's description is an implementation detail of its source, this /// should generally not be called outside of [Source] subclasses. A reference /// can be obtained from a user-supplied description using [Source.parseRef]. - PackageRef(String name, Source source, description) + PackageRef(String name, Source? source, description) : super._(name, source, description); /// Creates a reference to the given root package. PackageRef.root(Package package) : super._(package.name, null, package.name); @override - String toString([PackageDetail detail]) { + String toString([PackageDetail? detail]) { detail ??= PackageDetail.defaults; if (isRoot) return name; @@ -97,7 +99,7 @@ if (detail.showSource ?? source is! HostedSource) { buffer.write(' from $source'); if (detail.showDescription) { - buffer.write(' ${source.formatDescription(description)}'); + buffer.write(' ${source!.formatDescription(description)}'); } } @@ -106,6 +108,9 @@ @override bool operator ==(other) => other is PackageRef && samePackage(other); + + @override + int get hashCode => super.hashCode ^ 'PackageRef'.hashCode; } /// A reference to a specific version of a package. @@ -130,7 +135,7 @@ /// /// Since an ID's description is an implementation detail of its source, this /// should generally not be called outside of [Source] subclasses. - PackageId(String name, Source source, this.version, description) + PackageId(String name, Source? source, this.version, description) : super._(name, source, description); /// Creates an ID for the given root package. @@ -149,7 +154,7 @@ PackageRange toRange() => withConstraint(version); @override - String toString([PackageDetail detail]) { + String toString([PackageDetail? detail]) { detail ??= PackageDetail.defaults; var buffer = StringBuffer(name); @@ -158,7 +163,7 @@ if (!isRoot && (detail.showSource ?? source is! HostedSource)) { buffer.write(' from $source'); if (detail.showDescription) { - buffer.write(' ${source.formatDescription(description)}'); + buffer.write(' ${source!.formatDescription(description)}'); } } @@ -179,8 +184,8 @@ /// /// Since an ID's description is an implementation detail of its source, this /// should generally not be called outside of [Source] subclasses. - PackageRange(String name, Source source, this.constraint, description, - {Map<String, FeatureDependency> features}) + PackageRange(String name, Source? source, this.constraint, description, + {Map<String, FeatureDependency>? features}) : features = features == null ? const {} : UnmodifiableMapView(Map.from(features)), @@ -220,7 +225,7 @@ } @override - String toString([PackageDetail detail]) { + String toString([PackageDetail? detail]) { detail ??= PackageDetail.defaults; var buffer = StringBuffer(name); @@ -231,7 +236,7 @@ if (!isRoot && (detail.showSource ?? source is! HostedSource)) { buffer.write(' from $source'); if (detail.showDescription) { - buffer.write(' ${source.formatDescription(description)}'); + buffer.write(' ${source!.formatDescription(description)}'); } } @@ -246,9 +251,7 @@ bool get _showVersionConstraint { if (isRoot) return false; if (!constraint.isAny) return true; - if (source is PathSource) return false; - if (source is GitSource) return false; - return true; + return source!.hasMultipleVersions; } /// Returns a new [PackageRange] with [features] merged with [this.features]. @@ -267,9 +270,10 @@ var range = constraint as VersionRange; if (!range.includeMin) return this; if (range.includeMax) return this; - if (range.min == null) return this; - if (range.max == range.min.nextBreaking.firstPreRelease) { - return withConstraint(VersionConstraint.compatibleWith(range.min)); + var min = range.min; + if (min == null) return this; + if (range.max == min.nextBreaking.firstPreRelease) { + return withConstraint(VersionConstraint.compatibleWith(min)); } else { return this; } @@ -328,13 +332,13 @@ /// If this is `null`, the version is shown for all packages other than root /// [PackageId]s or [PackageRange]s with `git` or `path` sources and `any` /// constraints. - final bool showVersion; + final bool? showVersion; /// Whether to show the package source. /// /// If this is `null`, the source is shown for all non-hosted, non-root /// packages. It's always `true` if [showDescription] is `true`. - final bool showSource; + final bool? showSource; /// Whether to show the package description. /// @@ -348,9 +352,9 @@ const PackageDetail( {this.showVersion, - bool showSource, - bool showDescription, - bool showFeatures}) + bool? showSource, + bool? showDescription, + bool? showFeatures}) : showSource = showDescription == true ? true : showSource, showDescription = showDescription ?? false, showFeatures = showFeatures ?? true; @@ -358,8 +362,8 @@ /// Returns a [PackageDetail] with the maximum amount of detail between [this] /// and [other]. PackageDetail max(PackageDetail other) => PackageDetail( - showVersion: showVersion || other.showVersion, - showSource: showSource || other.showSource, + showVersion: showVersion! || other.showVersion!, + showSource: showSource! || other.showSource!, showDescription: showDescription || other.showDescription, showFeatures: showFeatures || other.showFeatures); }
diff --git a/lib/src/progress.dart b/lib/src/progress.dart index 06ad9e9..b9c6931 100644 --- a/lib/src/progress.dart +++ b/lib/src/progress.dart
@@ -34,7 +34,7 @@ Progress(this._message, {bool fine = false}) { _stopwatch.start(); - var level = fine ? log.Level.FINE : log.Level.MESSAGE; + var level = fine ? log.Level.fine : log.Level.message; // The animation is only shown when it would be meaningful to a human. // That means we're writing a visible message to a TTY at normal log levels @@ -43,7 +43,7 @@ !log.verbosity.isLevelVisible(level) || log.json.enabled || fine || - log.verbosity.isLevelVisible(log.Level.FINE)) { + log.verbosity.isLevelVisible(log.Level.fine)) { // Not animating, so just log the start and wait until the task is // completed. log.write(level, '$_message...');
diff --git a/lib/src/pub_embeddable_command.dart b/lib/src/pub_embeddable_command.dart index 4240ad1..b9e59c6 100644 --- a/lib/src/pub_embeddable_command.dart +++ b/lib/src/pub_embeddable_command.dart
@@ -2,8 +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. -// @dart=2.10 +import 'package:meta/meta.dart'; +import 'package:usage/usage.dart'; +import 'command.dart' show PubCommand, PubTopLevel; import 'command.dart'; import 'command/add.dart'; import 'command/build.dart'; @@ -24,6 +26,22 @@ import 'log.dart' as log; import 'log.dart'; +/// The information needed for the embedded pub command to send analytics. +@sealed +class PubAnalytics { + /// Name of the custom dimension of the dependency kind. + final String dependencyKindCustomDimensionName; + + final Analytics? Function() _analyticsGetter; + + Analytics? get analytics => _analyticsGetter(); + + PubAnalytics( + this._analyticsGetter, { + required this.dependencyKindCustomDimensionName, + }); +} + /// Exposes the `pub` commands as a command to be embedded in another command /// runner such as `dart pub`. class PubEmbeddableCommand extends PubCommand implements PubTopLevel { @@ -37,11 +55,16 @@ @override String get directory => argResults['directory']; - PubEmbeddableCommand() : super() { + @override + final PubAnalytics? analytics; + + final bool Function() isVerbose; + + PubEmbeddableCommand(this.analytics, this.isVerbose) : super() { argParser.addFlag('trace', help: 'Print debugging information when an error occurs.'); argParser.addFlag('verbose', - abbr: 'v', negatable: false, help: 'Shortcut for "--verbosity=all".'); + abbr: 'v', negatable: false, help: 'Print detailed logging.'); argParser.addOption( 'directory', abbr: 'C', @@ -80,12 +103,15 @@ } @override - bool get captureStackChains => argResults['verbose']; + bool get captureStackChains => _isVerbose; @override - Verbosity get verbosity => - argResults['verbose'] ? Verbosity.ALL : Verbosity.NORMAL; + Verbosity get verbosity => _isVerbose ? Verbosity.all : Verbosity.normal; @override - bool get trace => argResults['verbose']; + bool get trace => _isVerbose; + + bool get _isVerbose { + return argResults['verbose'] || isVerbose(); + } }
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index 5a3d3c0..cc75b2d 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart
@@ -2,12 +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. -// @dart=2.10 - import 'dart:io'; import 'package:collection/collection.dart' hide mapMap; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'package:pub_semver/pub_semver.dart'; import 'package:source_span/source_span.dart'; @@ -19,23 +16,18 @@ import 'language_version.dart'; import 'log.dart'; import 'package_name.dart'; +import 'pubspec_parse.dart'; import 'sdk.dart'; import 'source_registry.dart'; import 'utils.dart'; -/// A regular expression matching allowed package names. -/// -/// This allows dot-separated valid Dart identifiers. The dots are there for -/// compatibility with Google's internal Dart packages, but they may not be used -/// when publishing a package to pub.dartlang.org. -final _packageName = - RegExp('^${identifierRegExp.pattern}(\\.${identifierRegExp.pattern})*\$'); +export 'pubspec_parse.dart' hide PubspecBase; /// The default SDK upper bound constraint for packages that don't declare one. /// /// This provides a sane default for packages that don't have an upper bound. final VersionRange _defaultUpperBoundSdkConstraint = - VersionConstraint.parse('<2.0.0'); + VersionConstraint.parse('<2.0.0') as VersionRange; /// Whether or not to allow the pre-release SDK for packages that have an /// upper bound Dart SDK constraint of <2.0.0. @@ -72,7 +64,7 @@ /// accessed. This allows a partially-invalid pubspec to be used if only the /// valid portions are relevant. To get a list of all errors in the pubspec, use /// [allErrors]. -class Pubspec { +class Pubspec extends PubspecBase { // If a new lazily-initialized field is added to this class and the // initialization can throw a [PubspecException], that error should also be // exposed through [allErrors]. @@ -82,145 +74,64 @@ /// /// This will be null if this was created using [new Pubspec] or [new /// Pubspec.empty]. - final SourceRegistry _sources; + final SourceRegistry? _sources; /// The location from which the pubspec was loaded. /// /// This can be null if the pubspec was created in-memory or if its location /// is unknown. - Uri get _location => fields.span.sourceUrl; - - /// All pubspec fields. - /// - /// This includes the fields from which other properties are derived. - final YamlMap fields; - - /// Whether or not to apply the [_defaultUpperBoundsSdkConstraint] to this - /// pubspec. - final bool _includeDefaultSdkConstraint; - - /// Whether or not the SDK version was overridden from <2.0.0 to - /// <2.0.0-dev.infinity. - bool get dartSdkWasOverridden => _dartSdkWasOverridden; - bool _dartSdkWasOverridden = false; - - /// The package's name. - String get name { - if (_name != null) return _name; - - var name = fields['name']; - if (name == null) { - throw PubspecException('Missing the required "name" field.', fields.span); - } else if (name is! String) { - throw PubspecException( - '"name" field must be a string.', fields.nodes['name'].span); - } else if (!_packageName.hasMatch(name)) { - throw PubspecException('"name" field must be a valid Dart identifier.', - fields.nodes['name'].span); - } else if (reservedWords.contains(name)) { - throw PubspecException('"name" field may not be a Dart reserved word.', - fields.nodes['name'].span); - } - - _name = name; - return _name; - } - - String _name; - - /// The package's version. - Version get version { - if (_version != null) return _version; - - var version = fields['version']; - if (version == null) { - _version = Version.none; - return _version; - } - - var span = fields.nodes['version'].span; - if (version is num) { - var fixed = '$version.0'; - if (version is int) { - fixed = '$fixed.0'; - } - _error( - '"version" field must have three numeric components: major, ' - 'minor, and patch. Instead of "$version", consider "$fixed".', - span); - } - if (version is! String) { - _error('"version" field must be a string.', span); - } - - _version = _wrapFormatException( - 'version number', span, () => Version.parse(version)); - return _version; - } - - Version _version; + Uri? get _location => fields.span.sourceUrl; /// The additional packages this package depends on. - Map<String, PackageRange> get dependencies { - if (_dependencies != null) return _dependencies; - _dependencies = - _parseDependencies('dependencies', fields.nodes['dependencies']); - return _dependencies; - } + Map<String, PackageRange> get dependencies => _dependencies ??= + _parseDependencies('dependencies', fields.nodes['dependencies']); - Map<String, PackageRange> _dependencies; + Map<String, PackageRange>? _dependencies; /// The packages this package depends on when it is the root package. - Map<String, PackageRange> get devDependencies { - if (_devDependencies != null) return _devDependencies; - _devDependencies = _parseDependencies( - 'dev_dependencies', fields.nodes['dev_dependencies']); - return _devDependencies; - } + Map<String, PackageRange> get devDependencies => _devDependencies ??= + _parseDependencies('dev_dependencies', fields.nodes['dev_dependencies']); - Map<String, PackageRange> _devDependencies; + Map<String, PackageRange>? _devDependencies; /// The dependency constraints that this package overrides when it is the /// root package. /// /// Dependencies here will replace any dependency on a package with the same /// name anywhere in the dependency graph. - Map<String, PackageRange> get dependencyOverrides { - if (_dependencyOverrides != null) return _dependencyOverrides; - _dependencyOverrides = _parseDependencies( - 'dependency_overrides', fields.nodes['dependency_overrides']); - return _dependencyOverrides; - } + Map<String, PackageRange> get dependencyOverrides => + _dependencyOverrides ??= _parseDependencies( + 'dependency_overrides', fields.nodes['dependency_overrides']); - Map<String, PackageRange> _dependencyOverrides; + Map<String, PackageRange>? _dependencyOverrides; - Map<String, Feature> get features { - if (_features != null) return _features; - var features = fields['features']; + late final Map<String, Feature> features = _computeFeatures(); + + Map<String, Feature> _computeFeatures() { + final features = fields['features']; if (features == null) { - _features = const {}; - return _features; + return const {}; } - if (features is! Map) { - _error('"features" field must be a map.', fields.nodes['features'].span); + if (features is! YamlMap) { + _error('"features" field must be a map.', fields.nodes['features']!.span); } - _features = mapMap(features.nodes, - key: (nameNode, _) => _validateFeatureName(nameNode), - value: (nameNode, specNode) { + return mapMap(features.nodes, + key: (dynamic nameNode, dynamic _) => _validateFeatureName(nameNode), + value: (dynamic nameNode, dynamic specNode) { if (specNode.value == null) { return Feature(nameNode.value, const []); } - if (specNode is! Map) { + if (specNode is! YamlMap) { _error('A feature specification must be a map.', specNode.span); } var onByDefault = specNode['default'] ?? true; if (onByDefault is! bool) { _error('Default must be true or false.', - specNode.nodes['default'].span); + specNode.nodes['default']!.span); } var requires = _parseStringList(specNode.nodes['requires'], @@ -238,18 +149,24 @@ sdkConstraints: sdkConstraints, onByDefault: onByDefault); }); - return _features; } - Map<String, Feature> _features; - /// A map from SDK identifiers to constraints on those SDK versions. Map<String, VersionConstraint> get sdkConstraints { _ensureEnvironment(); - return _sdkConstraints; + return _sdkConstraints!; } - Map<String, VersionConstraint> _sdkConstraints; + Map<String, VersionConstraint>? _sdkConstraints; + + /// Whether or not to apply the [_defaultUpperBoundsSdkConstraint] to this + /// pubspec. + final bool _includeDefaultSdkConstraint; + + /// Whether or not the SDK version was overridden from <2.0.0 to + /// <2.0.0-dev.infinity. + bool get dartSdkWasOverridden => _dartSdkWasOverridden; + bool _dartSdkWasOverridden = false; /// The original Dart SDK constraint as written in the pubspec. /// @@ -257,10 +174,10 @@ /// `sdkConstraints["dart"]`. VersionConstraint get originalDartSdkConstraint { _ensureEnvironment(); - return _originalDartSdkConstraint ?? sdkConstraints['dart']; + return _originalDartSdkConstraint ?? sdkConstraints['dart']!; } - VersionConstraint _originalDartSdkConstraint; + VersionConstraint? _originalDartSdkConstraint; /// Ensures that the top-level "environment" field has been parsed and /// [_sdkConstraints] is set accordingly. @@ -300,17 +217,19 @@ if (!_allowPreReleaseSdk) return false; if (!sdk.version.isPreRelease) return false; if (sdkConstraint.includeMax) return false; - if (sdkConstraint.min != null && - sdkConstraint.min.isPreRelease && - equalsIgnoringPreRelease(sdkConstraint.min, sdk.version)) { + var minSdkConstraint = sdkConstraint.min; + if (minSdkConstraint != null && + minSdkConstraint.isPreRelease && + equalsIgnoringPreRelease(sdkConstraint.min!, sdk.version)) { return false; } - if (sdkConstraint.max == null) return false; - if (sdkConstraint.max.isPreRelease && - !sdkConstraint.max.isFirstPreRelease) { + var maxSdkConstraint = sdkConstraint.max; + if (maxSdkConstraint == null) return false; + if (maxSdkConstraint.max.isPreRelease && + !maxSdkConstraint.isFirstPreRelease) { return false; } - return equalsIgnoringPreRelease(sdkConstraint.max, sdk.version); + return equalsIgnoringPreRelease(maxSdkConstraint, sdk.version); } /// Parses the "environment" field in [parent] and returns a map from SDK @@ -325,9 +244,9 @@ }; } - if (yaml is! Map) { + if (yaml is! YamlMap) { _error('"environment" field must be a map.', - parent.nodes['environment'].span); + parent.nodes['environment']!.span); } var constraints = { @@ -353,141 +272,6 @@ return constraints; } - /// The URL of the server that the package should default to being published - /// to, "none" if the package should not be published, or `null` if it should - /// be published to the default server. - /// - /// If this does return a URL string, it will be a valid parseable URL. - String get publishTo { - if (_parsedPublishTo) return _publishTo; - - var publishTo = fields['publish_to']; - if (publishTo != null) { - var span = fields.nodes['publish_to'].span; - - if (publishTo is! String) { - _error('"publish_to" field must be a string.', span); - } - - // It must be "none" or a valid URL. - if (publishTo != 'none') { - _wrapFormatException('"publish_to" field', span, () { - var url = Uri.parse(publishTo); - if (url.scheme.isEmpty) { - throw FormatException('must be an absolute URL.'); - } - }); - } - } - - _parsedPublishTo = true; - _publishTo = publishTo; - return _publishTo; - } - - bool _parsedPublishTo = false; - String _publishTo; - - /// The list of patterns covering _false-positive secrets_ in the package. - /// - /// This is a list of git-ignore style patterns for files that should be - /// ignored when trying to detect possible leaks of secrets during - /// package publication. - List<String> get falseSecrets { - if (_falseSecrets == null) { - final falseSecrets = <String>[]; - - // Throws a [PubspecException] - void _falseSecretsError(SourceSpan span) => _error( - '"false_secrets" field must be a list of git-ignore style patterns', - span, - ); - - final falseSecretsNode = fields.nodes['false_secrets']; - if (falseSecretsNode != null) { - if (falseSecretsNode is YamlList) { - for (final node in falseSecretsNode.nodes) { - final value = node.value; - if (value is! String) { - _falseSecretsError(node.span); - } - falseSecrets.add(value); - } - } else { - _falseSecretsError(falseSecretsNode.span); - } - } - - _falseSecrets = List.unmodifiable(falseSecrets); - } - return _falseSecrets; - } - - List<String> _falseSecrets; - - /// The executables that should be placed on the user's PATH when this - /// package is globally activated. - /// - /// It is a map of strings to string. Each key is the name of the command - /// that will be placed on the user's PATH. The value is the name of the - /// .dart script (without extension) in the package's `bin` directory that - /// should be run for that command. Both key and value must be "simple" - /// strings: alphanumerics, underscores and hypens only. If a value is - /// omitted, it is inferred to use the same name as the key. - Map<String, String> get executables { - if (_executables != null) return _executables; - - _executables = {}; - var yaml = fields['executables']; - if (yaml == null) return _executables; - - if (yaml is! Map) { - _error('"executables" field must be a map.', - fields.nodes['executables'].span); - } - - yaml.nodes.forEach((key, value) { - if (key.value is! String) { - _error('"executables" keys must be strings.', key.span); - } - - final keyPattern = RegExp(r'^[a-zA-Z0-9_-]+$'); - if (!keyPattern.hasMatch(key.value)) { - _error( - '"executables" keys may only contain letters, ' - 'numbers, hyphens and underscores.', - key.span); - } - - if (value.value == null) { - value = key; - } else if (value.value is! String) { - _error('"executables" values must be strings or null.', value.span); - } - - final valuePattern = RegExp(r'[/\\]'); - if (valuePattern.hasMatch(value.value)) { - _error('"executables" values may not contain path separators.', - value.span); - } - - _executables[key.value] = value.value; - }); - - return _executables; - } - - Map<String, String> _executables; - - /// Whether the package is private and cannot be published. - /// - /// This is specified in the pubspec by setting "publish_to" to "none". - bool get isPrivate => publishTo == 'none'; - - /// Whether or not the pubspec has no contents. - bool get isEmpty => - name == null && version == Version.none && dependencies.isEmpty; - /// The language version implied by the sdk constraint. LanguageVersion get languageVersion => LanguageVersion.fromSdkConstraint(originalDartSdkConstraint); @@ -497,7 +281,7 @@ /// If [expectedName] is passed and the pubspec doesn't have a matching name /// field, this will throw a [PubspecException]. factory Pubspec.load(String packageDir, SourceRegistry sources, - {String expectedName}) { + {String? expectedName}) { var pubspecPath = path.join(packageDir, 'pubspec.yaml'); var pubspecUri = path.toUri(pubspecPath); if (!fileExists(pubspecPath)) { @@ -513,16 +297,15 @@ expectedName: expectedName, location: pubspecUri); } - Pubspec(this._name, - {Version version, - Iterable<PackageRange> dependencies, - Iterable<PackageRange> devDependencies, - Iterable<PackageRange> dependencyOverrides, - Map fields, - SourceRegistry sources, - Map<String, VersionConstraint> sdkConstraints}) - : _version = version, - _dependencies = dependencies == null + Pubspec(String name, + {Version? version, + Iterable<PackageRange>? dependencies, + Iterable<PackageRange>? devDependencies, + Iterable<PackageRange>? dependencyOverrides, + Map? fields, + SourceRegistry? sources, + Map<String, VersionConstraint>? sdkConstraints}) + : _dependencies = dependencies == null ? null : Map.fromIterable(dependencies, key: (range) => range.name), _devDependencies = devDependencies == null @@ -534,18 +317,22 @@ _sdkConstraints = sdkConstraints ?? UnmodifiableMapView({'dart': VersionConstraint.any}), _includeDefaultSdkConstraint = false, - fields = fields == null ? YamlMap() : YamlMap.wrap(fields), - _sources = sources; - + _sources = sources, + super( + fields == null ? YamlMap() : YamlMap.wrap(fields), + name: name, + version: version, + ); Pubspec.empty() : _sources = null, - _name = null, - _version = Version.none, _dependencies = {}, _devDependencies = {}, _sdkConstraints = {'dart': VersionConstraint.any}, _includeDefaultSdkConstraint = false, - fields = YamlMap(); + super( + YamlMap(), + version: Version.none, + ); /// Returns a Pubspec object for an already-parsed map representing its /// contents. @@ -555,11 +342,11 @@ /// /// [location] is the location from which this pubspec was loaded. Pubspec.fromMap(Map fields, this._sources, - {String expectedName, Uri location}) - : fields = fields is YamlMap + {String? expectedName, Uri? location}) + : _includeDefaultSdkConstraint = true, + super(fields is YamlMap ? fields - : YamlMap.wrap(fields, sourceUrl: location), - _includeDefaultSdkConstraint = true { + : YamlMap.wrap(fields, sourceUrl: location)) { // If [expectedName] is passed, ensure that the actual 'name' field exists // and matches the expectation. if (expectedName == null) return; @@ -568,7 +355,7 @@ throw PubspecException( '"name" field doesn\'t match expected name ' '"$expectedName".', - this.fields.nodes['name'].span); + this.fields.nodes['name']!.span); } /// Parses the pubspec stored at [filePath] whose text is [contents]. @@ -576,7 +363,7 @@ /// If the pubspec doesn't define a version for itself, it defaults to /// [Version.none]. factory Pubspec.parse(String contents, SourceRegistry sources, - {String expectedName, Uri location}) { + {String? expectedName, Uri? location}) { YamlNode pubspecNode; try { pubspecNode = loadYamlNode(contents, sourceUrl: location); @@ -625,7 +412,7 @@ /// Parses the dependency field named [field], and returns the corresponding /// map of dependency names to dependencies. - Map<String, PackageRange> _parseDependencies(String field, YamlNode node) { + Map<String, PackageRange> _parseDependencies(String field, YamlNode? node) { var dependencies = <String, PackageRange>{}; // Allow an empty dependencies key. @@ -635,31 +422,28 @@ _error('"$field" field must be a map.', node.span); } - var map = node as YamlMap; - var nonStringNode = map.nodes.keys + var nonStringNode = node.nodes.keys .firstWhere((e) => e.value is! String, orElse: () => null); if (nonStringNode != null) { _error('A dependency name must be a string.', nonStringNode.span); } - map.nodes.forEach((nameNode, specNode) { + node.nodes.forEach((nameNode, specNode) { var name = nameNode.value; var spec = specNode.value; if (fields['name'] != null && name == this.name) { _error('A package may not list itself as a dependency.', nameNode.span); } - YamlNode descriptionNode; - String sourceName; + YamlNode? descriptionNode; + String? sourceName; VersionConstraint versionConstraint = VersionRange(); var features = const <String, FeatureDependency>{}; if (spec == null) { - descriptionNode = nameNode; - sourceName = _sources.defaultSource.name; + sourceName = _sources!.defaultSource.name; } else if (spec is String) { - descriptionNode = nameNode; - sourceName = _sources.defaultSource.name; + sourceName = _sources!.defaultSource.name; versionConstraint = _parseVersionConstraint(specNode); } else if (spec is Map) { // Don't write to the immutable YAML map. @@ -682,7 +466,6 @@ } else if (sourceNames.isEmpty) { // Default to a hosted dependency if no source is specified. sourceName = 'hosted'; - descriptionNode = nameNode; } sourceName ??= sourceNames.single; @@ -699,13 +482,18 @@ // Let the source validate the description. var ref = _wrapFormatException('description', descriptionNode?.span, () { - String pubspecPath; - if (_location != null && _isFileUri(_location)) { + String? pubspecPath; + var location = _location; + if (location != null && _isFileUri(location)) { pubspecPath = path.fromUri(_location); } - return _sources[sourceName].parseRef(name, descriptionNode?.value, - containingPath: pubspecPath); + return _sources![sourceName]!.parseRef( + name, + descriptionNode?.value, + containingPath: pubspecPath, + languageVersion: languageVersion, + ); }, targetPackage: name); dependencies[name] = @@ -722,13 +510,13 @@ /// bound and it is compatible with [defaultUpperBoundConstraint]. /// /// If [ignoreUpperBound] the max constraint is ignored. - VersionConstraint _parseVersionConstraint(YamlNode node, - {VersionConstraint defaultUpperBoundConstraint, + VersionConstraint _parseVersionConstraint(YamlNode? node, + {VersionConstraint? defaultUpperBoundConstraint, bool ignoreUpperBound = false}) { if (node?.value == null) { return defaultUpperBoundConstraint ?? VersionConstraint.any; } - if (node.value is! String) { + if (node!.value is! String) { _error('A version constraint must be a string.', node.span); } @@ -751,13 +539,13 @@ /// Parses [node] to a map from feature names to whether those features are /// enabled. - Map<String, FeatureDependency> _parseDependencyFeatures(YamlNode node) { + Map<String, FeatureDependency> _parseDependencyFeatures(YamlNode? node) { if (node?.value == null) return const {}; - if (node is! YamlMap) _error('Features must be a map.', node.span); + if (node is! YamlMap) _error('Features must be a map.', node!.span); - return mapMap((node as YamlMap).nodes, - key: (nameNode, _) => _validateFeatureName(nameNode), - value: (_, valueNode) { + return mapMap(node.nodes, + key: (dynamic nameNode, dynamic _) => _validateFeatureName(nameNode), + value: (dynamic _, dynamic valueNode) { var value = valueNode.value; if (value is bool) { return value @@ -778,7 +566,7 @@ var name = node.value; if (name is! String) { _error('A feature name must be a string.', node.span); - } else if (!_packageName.hasMatch(name)) { + } else if (!packageNameRegExp.hasMatch(name)) { _error('A feature name must be a valid Dart identifier.', node.span); } @@ -788,8 +576,8 @@ /// Verifies that [node] is a list of strings and returns it. /// /// If [validate] is passed, it's called for each string in [node]. - List<String> _parseStringList(YamlNode node, - {void Function(String value, SourceSpan) validate}) { + List<String> _parseStringList(YamlNode? node, + {void Function(String value, SourceSpan)? validate}) { var list = _parseList(node); for (var element in list.nodes) { var value = element.value; @@ -803,7 +591,7 @@ } /// Verifies that [node] is a list and returns it. - YamlList _parseList(YamlNode node) { + YamlList _parseList(YamlNode? node) { if (node == null || node.value == null) return YamlList(); if (node is YamlList) return node; _error('Must be a list.', node.span); @@ -819,11 +607,14 @@ /// If [targetPackage] is provided, the value is used to describe the /// dependency that caused the problem. T _wrapFormatException<T>( - String description, SourceSpan span, T Function() fn, - {String targetPackage}) { + String description, SourceSpan? span, T Function() fn, + {String? targetPackage}) { try { return fn(); } on FormatException catch (e) { + // If we already have a pub exception with a span, re-use that + if (e is PubspecException) rethrow; + var msg = 'Invalid $description'; if (targetPackage != null) { msg = '$msg in the "$name" pubspec on the "$targetPackage" dependency'; @@ -834,20 +625,11 @@ } /// Throws a [PubspecException] with the given message. - @alwaysThrows - void _error(String message, SourceSpan span) { + Never _error(String message, SourceSpan? span) { throw PubspecException(message, span); } } -/// An exception thrown when parsing a pubspec. -/// -/// These exceptions are often thrown lazily while accessing pubspec properties. -class PubspecException extends SourceSpanFormatException - implements ApplicationException { - PubspecException(String message, SourceSpan span) : super(message, span); -} - /// Returns whether [uri] is a file URI. /// /// This is slightly more complicated than just checking if the scheme is
diff --git a/lib/src/pubspec_parse.dart b/lib/src/pubspec_parse.dart new file mode 100644 index 0000000..68f9ce7 --- /dev/null +++ b/lib/src/pubspec_parse.dart
@@ -0,0 +1,262 @@ +// Copyright (c) 2021, 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 'package:meta/meta.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:source_span/source_span.dart'; +import 'package:yaml/yaml.dart'; + +import 'exceptions.dart' show ApplicationException; +import 'utils.dart' show identifierRegExp, reservedWords; + +/// A regular expression matching allowed package names. +/// +/// This allows dot-separated valid Dart identifiers. The dots are there for +/// compatibility with Google's internal Dart packages, but they may not be used +/// when publishing a package to pub.dartlang.org. +final packageNameRegExp = + RegExp('^${identifierRegExp.pattern}(\\.${identifierRegExp.pattern})*\$'); + +/// Helper class for pubspec parsing to: +/// - extract the fields and methods that are reusable outside of `pub` client, and +/// - help null-safety migration a bit. +/// +/// This class should be eventually extracted to a separate library, or re-merged with `Pubspec`. +abstract class PubspecBase { + /// All pubspec fields. + /// + /// This includes the fields from which other properties are derived. + final YamlMap fields; + + PubspecBase( + this.fields, { + String? name, + Version? version, + }) : _name = name, + _version = version; + + /// The package's name. + String get name => _name ??= _lookupName(); + + String _lookupName() { + final name = fields['name']; + if (name == null) { + throw PubspecException('Missing the required "name" field.', fields.span); + } else if (name is! String) { + throw PubspecException( + '"name" field must be a string.', fields.nodes['name']?.span); + } else if (!packageNameRegExp.hasMatch(name)) { + throw PubspecException('"name" field must be a valid Dart identifier.', + fields.nodes['name']?.span); + } else if (reservedWords.contains(name)) { + throw PubspecException('"name" field may not be a Dart reserved word.', + fields.nodes['name']?.span); + } + + return name; + } + + String? _name; + + /// The package's version. + Version get version { + if (_version != null) return _version!; + + final version = fields['version']; + if (version == null) { + _version = Version.none; + return _version!; + } + + final span = fields.nodes['version']?.span; + if (version is num) { + var fixed = '$version.0'; + if (version is int) { + fixed = '$fixed.0'; + } + _error( + '"version" field must have three numeric components: major, ' + 'minor, and patch. Instead of "$version", consider "$fixed".', + span); + } + if (version is! String) { + _error('"version" field must be a string.', span); + } + + _version = _wrapFormatException( + 'version number', span, () => Version.parse(version)); + return _version!; + } + + Version? _version; + + /// The URL of the server that the package should default to being published + /// to, "none" if the package should not be published, or `null` if it should + /// be published to the default server. + /// + /// If this does return a URL string, it will be a valid parseable URL. + String? get publishTo { + if (_parsedPublishTo) return _publishTo; + + final publishTo = fields['publish_to']; + if (publishTo != null) { + final span = fields.nodes['publish_to']?.span; + + if (publishTo is! String) { + _error('"publish_to" field must be a string.', span); + } + + // It must be "none" or a valid URL. + if (publishTo != 'none') { + _wrapFormatException('"publish_to" field', span, () { + final url = Uri.parse(publishTo); + if (url.scheme.isEmpty) { + throw FormatException('must be an absolute URL.'); + } + }); + } + } + + _parsedPublishTo = true; + _publishTo = publishTo; + return _publishTo; + } + + bool _parsedPublishTo = false; + String? _publishTo; + + /// The list of patterns covering _false-positive secrets_ in the package. + /// + /// This is a list of git-ignore style patterns for files that should be + /// ignored when trying to detect possible leaks of secrets during + /// package publication. + List<String> get falseSecrets { + if (_falseSecrets == null) { + final falseSecrets = <String>[]; + + // Throws a [PubspecException] + void _falseSecretsError(SourceSpan span) => _error( + '"false_secrets" field must be a list of git-ignore style patterns', + span, + ); + + final falseSecretsNode = fields.nodes['false_secrets']; + if (falseSecretsNode != null) { + if (falseSecretsNode is YamlList) { + for (final node in falseSecretsNode.nodes) { + final value = node.value; + if (value is! String) { + _falseSecretsError(node.span); + } + falseSecrets.add(value); + } + } else { + _falseSecretsError(falseSecretsNode.span); + } + } + + _falseSecrets = List.unmodifiable(falseSecrets); + } + return _falseSecrets!; + } + + List<String>? _falseSecrets; + + /// The executables that should be placed on the user's PATH when this + /// package is globally activated. + /// + /// It is a map of strings to string. Each key is the name of the command + /// that will be placed on the user's PATH. The value is the name of the + /// .dart script (without extension) in the package's `bin` directory that + /// should be run for that command. Both key and value must be "simple" + /// strings: alphanumerics, underscores and hypens only. If a value is + /// omitted, it is inferred to use the same name as the key. + Map<String, String> get executables { + if (_executables != null) return _executables!; + + _executables = {}; + var yaml = fields['executables']; + if (yaml == null) return _executables!; + + if (yaml is! Map) { + _error('"executables" field must be a map.', + fields.nodes['executables']?.span); + } + + yaml.nodes.forEach((key, value) { + if (key.value is! String) { + _error('"executables" keys must be strings.', key.span); + } + + final keyPattern = RegExp(r'^[a-zA-Z0-9_-]+$'); + if (!keyPattern.hasMatch(key.value)) { + _error( + '"executables" keys may only contain letters, ' + 'numbers, hyphens and underscores.', + key.span); + } + + if (value.value == null) { + value = key; + } else if (value.value is! String) { + _error('"executables" values must be strings or null.', value.span); + } + + final valuePattern = RegExp(r'[/\\]'); + if (valuePattern.hasMatch(value.value)) { + _error('"executables" values may not contain path separators.', + value.span); + } + + _executables![key.value] = value.value; + }); + + return _executables!; + } + + Map<String, String>? _executables; + + /// Whether the package is private and cannot be published. + /// + /// This is specified in the pubspec by setting "publish_to" to "none". + bool get isPrivate => publishTo == 'none'; + + /// Runs [fn] and wraps any [FormatException] it throws in a + /// [PubspecException]. + /// + /// [description] should be a noun phrase that describes whatever's being + /// parsed or processed by [fn]. [span] should be the location of whatever's + /// being processed within the pubspec. + /// + /// If [targetPackage] is provided, the value is used to describe the + /// dependency that caused the problem. + T _wrapFormatException<T>( + String description, SourceSpan? span, T Function() fn, + {String? targetPackage}) { + try { + return fn(); + } on FormatException catch (e) { + var msg = 'Invalid $description'; + if (targetPackage != null) { + msg = '$msg in the "$name" pubspec on the "$targetPackage" dependency'; + } + msg = '$msg: ${e.message}'; + throw PubspecException(msg, span); + } + } + + /// Throws a [PubspecException] with the given message. + @alwaysThrows + void _error(String message, SourceSpan? span) { + throw PubspecException(message, span); + } +} + +/// An exception thrown when parsing a pubspec. +/// +/// These exceptions are often thrown lazily while accessing pubspec properties. +class PubspecException extends SourceSpanFormatException + implements ApplicationException { + PubspecException(String message, SourceSpan? span) : super(message, span); +}
diff --git a/lib/src/pubspec_utils.dart b/lib/src/pubspec_utils.dart index d58fb62..ee904a7 100644 --- a/lib/src/pubspec_utils.dart +++ b/lib/src/pubspec_utils.dart
@@ -2,7 +2,7 @@ // 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. -// @dart=2.10 +import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; @@ -42,7 +42,7 @@ Future<Pubspec> constrainedToAtLeastNullSafetyPubspec( Pubspec original, SystemCache cache) async { /// Get the first version of [package] opting in to null-safety. - Future<VersionRange> constrainToFirstWithNullSafety( + Future<VersionConstraint> constrainToFirstWithNullSafety( PackageRange packageRange) async { final ref = packageRange.toRef(); final available = await cache.source(ref.source).getVersions(ref); @@ -65,7 +65,7 @@ Map<String, PackageRange> constrained, ) async { final result = await Future.wait(constrained.keys.map((name) async { - final packageRange = constrained[name]; + final packageRange = constrained[name]!; var unconstrainedRange = packageRange; /// We only need to remove the upper bound if it is a hosted package. @@ -106,7 +106,7 @@ /// not specified or empty, then all packages will have their upper bounds /// removed. Pubspec stripVersionUpperBounds(Pubspec original, - {Iterable<String> stripOnly}) { + {Iterable<String>? stripOnly}) { ArgumentError.checkNotNull(original, 'original'); stripOnly ??= []; @@ -116,12 +116,12 @@ final result = <PackageRange>[]; for (final name in constrained.keys) { - final packageRange = constrained[name]; + final packageRange = constrained[name]!; var unconstrainedRange = packageRange; /// We only need to remove the upper bound if it is a hosted package. if (packageRange.source is HostedSource && - (stripOnly.isEmpty || stripOnly.contains(packageRange.name))) { + (stripOnly!.isEmpty || stripOnly.contains(packageRange.name))) { unconstrainedRange = PackageRange( packageRange.name, packageRange.source,
diff --git a/lib/src/rate_limited_scheduler.dart b/lib/src/rate_limited_scheduler.dart index 6e62310..85d73cd 100644 --- a/lib/src/rate_limited_scheduler.dart +++ b/lib/src/rate_limited_scheduler.dart
@@ -2,13 +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. -// @dart=2.10 - import 'dart:async'; import 'dart:collection'; -import 'package:meta/meta.dart'; -import 'package:pedantic/pedantic.dart'; import 'package:pool/pool.dart'; /// Handles rate-limited scheduling of tasks. @@ -65,7 +61,7 @@ final Set<J> _started = {}; RateLimitedScheduler(Future<V> Function(J) runJob, - {@required int maxConcurrentOperations}) + {required int maxConcurrentOperations}) : _runJob = runJob, _pool = Pool(maxConcurrentOperations); @@ -77,7 +73,7 @@ return; } final task = _queue.removeFirst(); - final completer = _cache[task.jobId]; + final completer = _cache[task.jobId]!; if (!_started.add(task.jobId)) { return; @@ -95,7 +91,9 @@ // become uncaught. // // They will still show up for other listeners of the future. - await completer.future.catchError((_) {}); + try { + await completer.future; + } catch (_) {} } /// Calls [callback] with a function that can pre-schedule jobs. @@ -140,7 +138,7 @@ /// Returns the result of running [jobId] if that is already done. /// Otherwise returns `null`. - V peek(J jobId) => _results[jobId]; + V? peek(J jobId) => _results[jobId]; } class _Task<J> {
diff --git a/lib/src/solver.dart b/lib/src/solver.dart index 18d3c23..74dbfa8 100644 --- a/lib/src/solver.dart +++ b/lib/src/solver.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'lock_file.dart'; @@ -33,8 +31,8 @@ SolveType type, SystemCache cache, Package root, { - LockFile lockFile, - Iterable<String> unlock, + LockFile? lockFile, + Iterable<String> unlock = const [], }) { lockFile ??= LockFile.empty(); return VersionSolver( @@ -42,7 +40,7 @@ cache, root, lockFile, - unlock ?? [], + unlock, ).solve(); } @@ -60,12 +58,12 @@ /// If [unlock] is empty [SolveType.get] interprets this as lock everything, /// while [SolveType.upgrade] and [SolveType.downgrade] interprets an empty /// [unlock] as unlock everything. -Future<SolveResult> tryResolveVersions( +Future<SolveResult?> tryResolveVersions( SolveType type, SystemCache cache, Package root, { - LockFile lockFile, - Iterable<String> unlock, + LockFile? lockFile, + Iterable<String>? unlock, }) async { try { return await resolveVersions( @@ -73,7 +71,7 @@ cache, root, lockFile: lockFile, - unlock: unlock, + unlock: unlock ?? [], ); } on SolveFailure { return null;
diff --git a/lib/src/solver/assignment.dart b/lib/src/solver/assignment.dart index 645eafb..d4c7bdf 100644 --- a/lib/src/solver/assignment.dart +++ b/lib/src/solver/assignment.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../package_name.dart'; import 'incompatibility.dart'; import 'term.dart'; @@ -19,7 +17,7 @@ /// The incompatibility that caused this assignment to be derived, or `null` /// if the assignment isn't a derivation. - final Incompatibility cause; + final Incompatibility? cause; /// Whether this assignment is a decision, as opposed to a derivation. bool get isDecision => cause == null;
diff --git a/lib/src/solver/failure.dart b/lib/src/solver/failure.dart index 1a3897b..60f70c5 100644 --- a/lib/src/solver/failure.dart +++ b/lib/src/solver/failure.dart
@@ -2,14 +2,11 @@ // 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. -// @dart=2.10 - import 'package:collection/collection.dart'; import '../exceptions.dart'; import '../log.dart' as log; import '../package_name.dart'; -import '../sdk.dart'; import '../utils.dart'; import 'incompatibility.dart'; import 'incompatibility_cause.dart'; @@ -30,7 +27,7 @@ /// /// If multiple [PackageNotFoundException]s caused the error, it's undefined /// which one is returned. - PackageNotFoundException get packageNotFound { + PackageNotFoundException? get packageNotFound { for (var incompatibility in incompatibility.externalIncompatibilities) { var cause = incompatibility.cause; if (cause is PackageNotFoundCause) return cause.exception; @@ -70,7 +67,7 @@ /// incompatibility, and why its terms are incompatible. The number is /// optional and indicates the explicit number that should be associated with /// the line so it can be referred to later on. - final _lines = <Pair<String, int>>[]; + final _lines = <Pair<String, int?>>[]; // A map from incompatibilities to the line numbers that were written for // those incompatibilities. @@ -82,51 +79,33 @@ /// Populates [_derivations] for [incompatibility] and its transitive causes. void _countDerivations(Incompatibility incompatibility) { - if (_derivations.containsKey(incompatibility)) { - _derivations[incompatibility]++; - } else { - _derivations[incompatibility] = 1; + _derivations.update(incompatibility, (value) => value + 1, ifAbsent: () { var cause = incompatibility.cause; if (cause is ConflictCause) { _countDerivations(cause.conflict); _countDerivations(cause.other); } - } + return 1; + }); } String write() { var buffer = StringBuffer(); - // SDKs whose version constraints weren't matched. - var sdkConstraintCauses = <Sdk>{}; - - // SDKs implicated in any way in the solve failure. - var sdkCauses = <Sdk>{}; - - for (var incompatibility in _root.externalIncompatibilities) { - var cause = incompatibility.cause; - if (cause is PackageNotFoundCause && cause.sdk != null) { - sdkCauses.add(cause.sdk); - } else if (cause is SdkCause) { - sdkCauses.add(cause.sdk); - sdkConstraintCauses.add(cause.sdk); - } + // Find all notices from incompatibility causes. This allows an + // [IncompatibilityCause] to provide a notice that is printed before the + // explanation of the conflict. + // Notably, this is used for stating which SDK version is currently + // installed, if an SDK is incompatible with a dependency. + final notices = _root.externalIncompatibilities + .map((c) => c.cause.notice) + .whereNotNull() + .toSet() // Avoid duplicates + .sortedBy((n) => n); // sort for consistency + for (final n in notices) { + buffer.writeln(n); } - - // If the failure was caused in part by unsatisfied SDK constraints, - // indicate the actual versions so we don't have to list them (possibly - // multiple times) in the main body of the error message. - // - // Iterate through [sdks] to ensure that SDKs versions are printed in a - // consistent order - var wroteLine = false; - for (var sdk in sdks.values) { - if (!sdkConstraintCauses.contains(sdk)) continue; - if (!sdk.isAvailable) continue; - wroteLine = true; - buffer.writeln('The current ${sdk.name} SDK version is ${sdk.version}.'); - } - if (wroteLine) buffer.writeln(); + if (notices.isNotEmpty) buffer.writeln(); if (_root.cause is ConflictCause) { _visit(_root, const {}); @@ -160,15 +139,21 @@ buffer.writeln(wordWrap(message, prefix: ' ' * (padding + 2))); } - // Iterate through [sdks] to ensure that SDKs versions are printed in a - // consistent order - for (var sdk in sdks.values) { - if (!sdkCauses.contains(sdk)) continue; - if (sdk.isAvailable) continue; - if (sdk.installMessage == null) continue; + // Iterate through all hints, these are intended to be actionable, such as: + // * How to install an SDK, and, + // * How to provide authentication. + // Hence, it makes sense to show these at the end of the explanation, as the + // user will ideally see these before reading the actual conflict and + // understand how to fix the issue. + _root.externalIncompatibilities + .map((c) => c.cause.hint) + .whereNotNull() + .toSet() // avoid duplicates + .sortedBy((hint) => hint) // sort hints for consistent ordering. + .forEach((hint) { buffer.writeln(); - buffer.writeln(sdk.installMessage); - } + buffer.writeln(hint); + }); return buffer.toString(); } @@ -203,23 +188,24 @@ {bool conclusion = false}) { // Add explicit numbers for incompatibilities that are written far away // from their successors or that are used for multiple derivations. - var numbered = conclusion || _derivations[incompatibility] > 1; + var numbered = conclusion || _derivations[incompatibility]! > 1; var conjunction = conclusion || incompatibility == _root ? 'So,' : 'And'; var incompatibilityString = log.bold(incompatibility.toString(detailsForIncompatibility)); - var cause = incompatibility.cause as ConflictCause; - var detailsForCause = _detailsForCause(cause); - if (cause.conflict.cause is ConflictCause && - cause.other.cause is ConflictCause) { - var conflictLine = _lineNumbers[cause.conflict]; - var otherLine = _lineNumbers[cause.other]; + var conflictClause = incompatibility.cause as ConflictCause; + var detailsForCause = _detailsForCause(conflictClause); + var cause = conflictClause.conflict.cause; + var otherCause = conflictClause.other.cause; + if (cause is ConflictCause && otherCause is ConflictCause) { + var conflictLine = _lineNumbers[conflictClause.conflict]; + var otherLine = _lineNumbers[conflictClause.other]; if (conflictLine != null && otherLine != null) { _write( incompatibility, 'Because ' + - cause.conflict.andToString( - cause.other, detailsForCause, conflictLine, otherLine) + + conflictClause.conflict.andToString(conflictClause.other, + detailsForCause, conflictLine, otherLine) + ', $incompatibilityString.', numbered: numbered); } else if (conflictLine != null || otherLine != null) { @@ -227,13 +213,13 @@ Incompatibility withoutLine; int line; if (conflictLine != null) { - withLine = cause.conflict; - withoutLine = cause.other; + withLine = conflictClause.conflict; + withoutLine = conflictClause.other; line = conflictLine; } else { - withLine = cause.other; - withoutLine = cause.conflict; - line = otherLine; + withLine = conflictClause.other; + withoutLine = conflictClause.conflict; + line = otherLine!; } _visit(withoutLine, detailsForCause); @@ -243,35 +229,38 @@ '($line), $incompatibilityString.', numbered: numbered); } else { - var singleLineConflict = _isSingleLine(cause.conflict.cause); - var singleLineOther = _isSingleLine(cause.other.cause); + var singleLineConflict = _isSingleLine(cause); + var singleLineOther = _isSingleLine(otherCause); if (singleLineOther || singleLineConflict) { - var first = singleLineOther ? cause.conflict : cause.other; - var second = singleLineOther ? cause.other : cause.conflict; + var first = + singleLineOther ? conflictClause.conflict : conflictClause.other; + var second = + singleLineOther ? conflictClause.other : conflictClause.conflict; _visit(first, detailsForCause); _visit(second, detailsForCause); _write(incompatibility, 'Thus, $incompatibilityString.', numbered: numbered); } else { - _visit(cause.conflict, {}, conclusion: true); + _visit(conflictClause.conflict, {}, conclusion: true); _lines.add(Pair('', null)); - _visit(cause.other, detailsForCause); + _visit(conflictClause.other, detailsForCause); _write( incompatibility, '$conjunction because ' - '${cause.conflict.toString(detailsForCause)} ' - '(${_lineNumbers[cause.conflict]}), ' + '${conflictClause.conflict.toString(detailsForCause)} ' + '(${_lineNumbers[conflictClause.conflict]}), ' '$incompatibilityString.', numbered: numbered); } } - } else if (cause.conflict.cause is ConflictCause || - cause.other.cause is ConflictCause) { - var derived = - cause.conflict.cause is ConflictCause ? cause.conflict : cause.other; - var ext = - cause.conflict.cause is ConflictCause ? cause.other : cause.conflict; + } else if (cause is ConflictCause || otherCause is ConflictCause) { + var derived = cause is ConflictCause + ? conflictClause.conflict + : conflictClause.other; + var ext = cause is ConflictCause + ? conflictClause.other + : conflictClause.conflict; var derivedLine = _lineNumbers[derived]; if (derivedLine != null) { @@ -313,7 +302,7 @@ _write( incompatibility, 'Because ' - '${cause.conflict.andToString(cause.other, detailsForCause)}, ' + '${conflictClause.conflict.andToString(conflictClause.other, detailsForCause)}, ' '$incompatibilityString.', numbered: numbered); } @@ -347,7 +336,7 @@ bool _isCollapsible(Incompatibility incompatibility) { // If [incompatibility] is used for multiple derivations, it will need a // line number and so will need to be written explicitly. - if (_derivations[incompatibility] > 1) return false; + if (_derivations[incompatibility]! > 1) return false; var cause = incompatibility.cause as ConflictCause; // If [incompatibility] is derived from two derived incompatibilities,
diff --git a/lib/src/solver/incompatibility.dart b/lib/src/solver/incompatibility.dart index 1dd6d96..9e39865 100644 --- a/lib/src/solver/incompatibility.dart +++ b/lib/src/solver/incompatibility.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub_semver/pub_semver.dart'; import '../package_name.dart'; @@ -67,14 +65,12 @@ var byRef = byName.putIfAbsent(term.package.name, () => {}); var ref = term.package.toRef(); if (byRef.containsKey(ref)) { - byRef[ref] = byRef[ref].intersect(term); - // If we have two terms that refer to the same package but have a null // intersection, they're mutually exclusive, making this incompatibility // irrelevant, since we already know that mutually exclusive version // ranges are incompatible. We should never derive an irrelevant // incompatibility. - assert(byRef[ref] != null); + byRef[ref] = byRef[ref]!.intersect(term)!; } else { byRef[ref] = term; } @@ -100,7 +96,7 @@ /// If [details] is passed, it controls the amount of detail that's written /// for packages with the given names. @override - String toString([Map<String, PackageDetail> details]) { + String toString([Map<String, PackageDetail>? details]) { if (cause == IncompatibilityCause.dependency) { assert(terms.length == 2); @@ -223,7 +219,7 @@ /// If [thisLine] and/or [otherLine] are passed, they indicate line numbers /// that should be associated with [this] and [other], respectively. String andToString(Incompatibility other, - [Map<String, PackageDetail> details, int thisLine, int otherLine]) { + [Map<String, PackageDetail>? details, int? thisLine, int? otherLine]) { var requiresBoth = _tryRequiresBoth(other, details, thisLine, otherLine); if (requiresBoth != null) return requiresBoth; @@ -246,8 +242,8 @@ /// and Y", this returns that expression. /// /// Otherwise, this returns `null`. - String _tryRequiresBoth(Incompatibility other, - [Map<String, PackageDetail> details, int thisLine, int otherLine]) { + String? _tryRequiresBoth(Incompatibility other, + [Map<String, PackageDetail>? details, int? thisLine, int? otherLine]) { if (terms.length == 1 || other.terms.length == 1) return null; var thisPositive = _singleTermWhere((term) => term.isPositive); @@ -281,8 +277,8 @@ /// Z", this returns that expression. /// /// Otherwise, this returns `null`. - String _tryRequiresThrough(Incompatibility other, - [Map<String, PackageDetail> details, int thisLine, int otherLine]) { + String? _tryRequiresThrough(Incompatibility other, + [Map<String, PackageDetail>? details, int? thisLine, int? otherLine]) { if (terms.length == 1 || other.terms.length == 1) return null; var thisNegative = _singleTermWhere((term) => !term.isPositive); @@ -294,9 +290,9 @@ Incompatibility prior; Term priorNegative; - int priorLine; + int? priorLine; Incompatibility latter; - int latterLine; + int? latterLine; if (thisNegative != null && otherPositive != null && thisNegative.package.name == otherPositive.package.name && @@ -358,14 +354,14 @@ /// forbidden", this returns that expression. /// /// Otherwise, this returns `null`. - String _tryRequiresForbidden(Incompatibility other, - [Map<String, PackageDetail> details, int thisLine, int otherLine]) { + String? _tryRequiresForbidden(Incompatibility other, + [Map<String, PackageDetail>? details, int? thisLine, int? otherLine]) { if (terms.length != 1 && other.terms.length != 1) return null; Incompatibility prior; Incompatibility latter; - int priorLine; - int latterLine; + int? priorLine; + int? latterLine; if (terms.length == 1) { prior = other; latter = this; @@ -439,8 +435,8 @@ /// term. /// /// Otherwise, returns `null`. - Term _singleTermWhere(bool Function(Term) filter) { - Term found; + Term? _singleTermWhere(bool Function(Term) filter) { + Term? found; for (var term in terms) { if (!filter(term)) continue; if (found != null) return null; @@ -450,7 +446,7 @@ } /// Returns a terse representation of [term]'s package ref. - String _terseRef(Term term, Map<String, PackageDetail> details) => + String _terseRef(Term term, Map<String, PackageDetail>? details) => term.package .toRef() .toString(details == null ? null : details[term.package.name]); @@ -459,12 +455,12 @@ /// /// If [allowEvery] is `true`, this will return "every version of foo" instead /// of "foo any". - String _terse(Term term, Map<String, PackageDetail> details, + String _terse(Term? term, Map<String, PackageDetail>? details, {bool allowEvery = false}) { - if (allowEvery && term.constraint.isAny) { + if (allowEvery && term!.constraint.isAny) { return 'every version of ${_terseRef(term, details)}'; } else { - return term.package + return term!.package .toString(details == null ? null : details[term.package.name]); } }
diff --git a/lib/src/solver/incompatibility_cause.dart b/lib/src/solver/incompatibility_cause.dart index 45aa5ca..a2a2327 100644 --- a/lib/src/solver/incompatibility_cause.dart +++ b/lib/src/solver/incompatibility_cause.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub_semver/pub_semver.dart'; import '../exceptions.dart'; @@ -12,6 +10,8 @@ /// The reason an [Incompatibility]'s terms are incompatible. abstract class IncompatibilityCause { + const IncompatibilityCause._(); + /// The incompatibility represents the requirement that the root package /// exists. static const IncompatibilityCause root = _Cause('root'); @@ -29,11 +29,26 @@ /// The incompatibility indicates that the package has an unknown source. static const IncompatibilityCause unknownSource = _Cause('unknown source'); + + /// Human readable notice / information providing context for this + /// incompatibility. + /// + /// This may be multiple lines, and will be printed before the explanation. + /// This is used highlight information that is useful for understanding the + /// why this conflict happened. + String? get notice => null; + + /// Human readable hint indicating how this incompatibility may be resolved. + /// + /// This may be multiple lines, and will be printed after the explanation. + /// This should only be included if it is actionable and likely to resolve the + /// issue for the user. + String? get hint => null; } /// The incompatibility was derived from two existing incompatibilities during /// conflict resolution. -class ConflictCause implements IncompatibilityCause { +class ConflictCause extends IncompatibilityCause { /// The incompatibility that was originally found to be in conflict, from /// which the target incompatibility was derived. final Incompatibility conflict; @@ -42,14 +57,14 @@ /// from which the target incompatibility was derived. final Incompatibility other; - ConflictCause(this.conflict, this.other); + ConflictCause(this.conflict, this.other) : super._(); } /// A class for stateless [IncompatibilityCause]s. -class _Cause implements IncompatibilityCause { +class _Cause extends IncompatibilityCause { final String _name; - const _Cause(this._name); + const _Cause(this._name) : super._(); @override String toString() => _name; @@ -57,27 +72,49 @@ /// The incompatibility represents a package's SDK constraint being /// incompatible with the current SDK. -class SdkCause implements IncompatibilityCause { +class SdkCause extends IncompatibilityCause { /// The union of all the incompatible versions' constraints on the SDK. - final VersionConstraint constraint; + // TODO(zarah): Investigate if this can be non-nullable + final VersionConstraint? constraint; /// The SDK with which the package was incompatible. final Sdk sdk; - SdkCause(this.constraint, this.sdk); + @override + String? get notice { + // If the SDK is not available, then we have an actionable [hint] printed + // after the explanation. So we don't need to state that the SDK is not + // available. + if (!sdk.isAvailable) { + return null; + } + // If the SDK is available and we have an incompatibility, then the user has + // the wrong SDK version (one that is not compatible with any solution). + // Thus, it makes sense to highlight the current SDK version. + return 'The current ${sdk.name} SDK version is ${sdk.version}.'; + } + + @override + String? get hint { + // If the SDK is available, then installing it won't help + if (sdk.isAvailable) { + return null; + } + // Return an install message for the SDK, if there is an install message. + return sdk.installMessage; + } + + SdkCause(this.constraint, this.sdk) : super._(); } /// The incompatibility represents a package that couldn't be found by its /// source. -class PackageNotFoundCause implements IncompatibilityCause { +class PackageNotFoundCause extends IncompatibilityCause { /// The exception indicating why the package couldn't be found. final PackageNotFoundException exception; - /// If the incompatibility was caused by an SDK being unavailable, this is - /// that SDK. - /// - /// Otherwise `null`. - Sdk get sdk => exception.missingSdk; + PackageNotFoundCause(this.exception) : super._(); - PackageNotFoundCause(this.exception); + @override + String? get hint => exception.hint; }
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart index 136b0db..8e1abed 100644 --- a/lib/src/solver/package_lister.dart +++ b/lib/src/solver/package_lister.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:async/async.dart'; @@ -34,7 +32,7 @@ /// /// This is `null` if this package isn't locked or if the current version /// solve isn't a `pub get`. - final PackageId _locked; + final PackageId? _locked; // The version of this package that, if retracted, is still allowed in the // current version solve. @@ -43,7 +41,7 @@ // present in `pubspec.lock` or pinned in `dependency_overrides`. // // This is `null` if there is no retracted version that can be allowed. - final Version _allowedRetractedVersion; + final Version? _allowedRetractedVersion; /// The source from which [_ref] comes. final BoundSource _source; @@ -78,25 +76,26 @@ /// The versions of [_ref] that have been downloaded and cached, or `null` if /// they haven't been downloaded yet. - List<PackageId> get cachedVersions => _cachedVersions; - List<PackageId> _cachedVersions; + List<PackageId>? get cachedVersions => _cachedVersions; + List<PackageId>? _cachedVersions; /// All versions of the package, sorted by [Version.compareTo]. Future<List<PackageId>> get _versions => _versionsMemo.runOnce(() async { - _cachedVersions = await withDependencyType( + var cachedVersions = (await withDependencyType( _dependencyType, () => _source.getVersions(_ref, - allowedRetractedVersion: _allowedRetractedVersion)); - _cachedVersions.sort((id1, id2) => id1.version.compareTo(id2.version)); - return _cachedVersions; + allowedRetractedVersion: _allowedRetractedVersion))) + ..sort((id1, id2) => id1.version.compareTo(id2.version)); + _cachedVersions = cachedVersions; + return cachedVersions; }); final _versionsMemo = AsyncMemoizer<List<PackageId>>(); /// The most recent version of this package (or the oldest, if we're /// downgrading). - Future<PackageId> get latest => + Future<PackageId?> get latest => _latestMemo.runOnce(() => bestVersion(VersionConstraint.any)); - final _latestMemo = AsyncMemoizer<PackageId>(); + final _latestMemo = AsyncMemoizer<PackageId?>(); /// Creates a package lister for the dependency identified by [ref]. PackageLister( @@ -125,7 +124,7 @@ /// Returns the number of versions of this package that match [constraint]. Future<int> countVersions(VersionConstraint constraint) async { - if (_locked != null && constraint.allows(_locked.version)) return 1; + if (_locked != null && constraint.allows(_locked!.version)) return 1; try { return (await _versions) .where((id) => constraint.allows(id.version)) @@ -144,32 +143,32 @@ /// /// Throws a [PackageNotFoundException] if this lister's package doesn't /// exist. - Future<PackageId> bestVersion(VersionConstraint constraint) async { - if (_locked != null && constraint.allows(_locked.version)) return _locked; + Future<PackageId?> bestVersion(VersionConstraint? constraint) async { + if (_locked != null && constraint!.allows(_locked!.version)) return _locked; var versions = await _versions; // If [constraint] has a minimum (or a maximum in downgrade mode), we can // bail early once we're past it. - var isPastLimit = (Version _) => false; + var isPastLimit = (Version? _) => false; if (constraint is VersionRange) { if (_isDowngrade) { var max = constraint.max; - if (max != null) isPastLimit = (version) => version > max; + if (max != null) isPastLimit = (version) => version! > max; } else { var min = constraint.min; - if (min != null) isPastLimit = (version) => version < min; + if (min != null) isPastLimit = (version) => version! < min; } } // Return the most preferable version that matches [constraint]: the latest // non-prerelease version if one exists, or the latest prerelease version // otherwise. - PackageId bestPrerelease; + PackageId? bestPrerelease; for (var id in _isDowngrade ? versions : versions.reversed) { - if (isPastLimit != null && isPastLimit(id.version)) break; + if (isPastLimit(id.version)) break; - if (!constraint.allows(id.version)) continue; + if (!constraint!.allows(id.version)) continue; if (!id.version.isPreRelease) return id; bestPrerelease ??= id; } @@ -210,7 +209,7 @@ if (_cachedVersions == null && _locked != null && - id.version == _locked.version) { + id.version == _locked!.version) { if (_listedLockedVersion) return const []; var depender = id.toRange(); @@ -252,7 +251,8 @@ var versions = await _versions; var index = lowerBound(versions, id, - compare: (id1, id2) => id1.version.compareTo(id2.version)); + compare: (dynamic id1, dynamic id2) => + id1.version.compareTo(id2.version)); assert(index < versions.length); assert(versions[index].version == id.version); @@ -289,7 +289,7 @@ _alreadyListedDependencies[package] ?? VersionConstraint.empty); return _dependency( - _ref.withConstraint(constraint), dependencies[package]); + _ref.withConstraint(constraint), dependencies[package]!); }).toList(); } @@ -303,7 +303,7 @@ /// version of [sdk], returns an [Incompatibility] indicating that. /// /// Otherwise, returns `null`. - Future<Incompatibility> _checkSdkConstraint(int index, Sdk sdk) async { + Future<Incompatibility?> _checkSdkConstraint(int index, Sdk sdk) async { var versions = await _versions; bool allowsSdk(Pubspec pubspec) => _matchesSdkConstraint(pubspec, sdk); @@ -322,7 +322,7 @@ var sdkConstraint = await foldAsync( slice(versions, bounds.first, bounds.last + 1), VersionConstraint.empty, - (previous, version) async { + (dynamic previous, dynamic version) async { var pubspec = await _describeSafe(version); return previous.union( pubspec.sdkConstraints[sdk.identifier] ?? VersionConstraint.any); @@ -364,7 +364,7 @@ /// If a package is absent from the return value, that indicates indicate that /// all versions above or below [index] (according to [upper]) have the same /// dependency. - Future<Map<String, Version>> _dependencyBounds( + Future<Map<String, Version?>> _dependencyBounds( Map<String, PackageRange> dependencies, int index, {bool upper = true}) async { var versions = await _versions; @@ -427,7 +427,7 @@ var constraint = pubspec.sdkConstraints[sdk.identifier]; if (constraint == null) return true; - return sdk.isAvailable && constraint.allows(sdk.version); + return sdk.isAvailable && constraint.allows(sdk.version!); } } @@ -447,7 +447,7 @@ @override Future<List<PackageId>> getVersions(PackageRef ref, - {Duration maxAge, Version allowedRetractedVersion}) { + {Duration? maxAge, Version? allowedRetractedVersion}) { assert(ref.isRoot); return Future.value([PackageId.root(_package)]); } @@ -463,11 +463,11 @@ @override SystemCache get systemCache => throw _unsupported; @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) => + Future<List<PackageId>> doGetVersions(PackageRef ref, Duration? maxAge) => throw _unsupported; @override Future<Pubspec> doDescribe(PackageId id) => throw _unsupported; @override - String getDirectory(PackageId id, {String relativeFrom}) => + String getDirectory(PackageId id, {String? relativeFrom}) => throw _unsupported; }
diff --git a/lib/src/solver/partial_solution.dart b/lib/src/solver/partial_solution.dart index 57c22bf..40d2611 100644 --- a/lib/src/solver/partial_solution.dart +++ b/lib/src/solver/partial_solution.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../package_name.dart'; import 'assignment.dart'; import 'incompatibility.dart'; @@ -27,7 +25,7 @@ /// negative [Assignment]s that refer to that package. /// /// This is derived from [_assignments]. - final _positive = <String, Term>{}; + final _positive = <String, Term?>{}; /// The union of all negative [Assignment]s for each package. /// @@ -43,8 +41,8 @@ /// Returns all [PackageRange]s that have been assigned but are not yet /// satisfied. Iterable<PackageRange> get unsatisfied => _positive.values - .where((term) => !_decisions.containsKey(term.package.name)) - .map((term) => term.package); + .where((term) => !_decisions.containsKey(term!.package.name)) + .map((term) => term!.package); // The current decision level—that is, the length of [decisions]. int get decisionLevel => _decisions.length; @@ -70,7 +68,7 @@ } /// Adds an assignment of [package] as a derivation. - void derive(PackageName package, bool isPositive, Incompatibility cause) { + void derive(PackageRange package, bool isPositive, Incompatibility cause) { _assign(Assignment.derivation( package, isPositive, cause, decisionLevel, _assignments.length)); } @@ -119,7 +117,7 @@ var negativeByRef = _negative[name]; var oldNegative = negativeByRef == null ? null : negativeByRef[ref]; var term = - oldNegative == null ? assignment : assignment.intersect(oldNegative); + oldNegative == null ? assignment : assignment.intersect(oldNegative)!; if (term.isPositive) { _negative.remove(name); @@ -134,7 +132,7 @@ /// /// Throws a [StateError] if [term] isn't satisfied by [this]. Assignment satisfier(Term term) { - Term assignedTerm; + Term? assignedTerm; for (var assignment in _assignments) { if (assignment.package.name != term.package.name) continue; @@ -153,7 +151,7 @@ : assignedTerm.intersect(assignment); // As soon as we have enough assignments to satisfy [term], return them. - if (assignedTerm.satisfies(term)) return assignment; + if (assignedTerm!.satisfies(term)) return assignment; } throw StateError('[BUG] $term is not satisfied.');
diff --git a/lib/src/solver/reformat_ranges.dart b/lib/src/solver/reformat_ranges.dart index bdb64b8..5c763a6 100644 --- a/lib/src/solver/reformat_ranges.dart +++ b/lib/src/solver/reformat_ranges.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:meta/meta.dart'; import 'package:pub_semver/pub_semver.dart'; import '../package_name.dart'; @@ -48,7 +47,7 @@ var range = term.package.constraint as VersionRange; var min = _reformatMin(versions, range); - var tuple = _reformatMax(versions, range); + var tuple = reformatMax(versions, range); var max = tuple?.first; var includeMax = tuple?.last; @@ -67,39 +66,46 @@ /// Returns the new minimum version to use for [range], or `null` if it doesn't /// need to be reformatted. -Version _reformatMin(List<PackageId> versions, VersionRange range) { - if (range.min == null) return null; +Version? _reformatMin(List<PackageId> versions, VersionRange range) { + var min = range.min; + if (min == null) return null; if (!range.includeMin) return null; - if (!range.min.isFirstPreRelease) return null; + if (!min.isFirstPreRelease) return null; - var index = _lowerBound(versions, range.min); + var index = _lowerBound(versions, min); var next = index == versions.length ? null : versions[index].version; // If there's a real pre-release version of [range.min], use that as the min. // Otherwise, use the release version. - return next != null && equalsIgnoringPreRelease(range.min, next) + return next != null && equalsIgnoringPreRelease(min, next) ? next - : Version(range.min.major, range.min.minor, range.min.patch); + : Version(min.major, min.minor, min.patch); } /// Returns the new maximum version to use for [range] and whether that maximum /// is inclusive, or `null` if it doesn't need to be reformatted. -Pair<Version, bool> _reformatMax(List<PackageId> versions, VersionRange range) { - if (range.max == null) return null; +@visibleForTesting +Pair<Version, bool>? reformatMax(List<PackageId> versions, VersionRange range) { + // This corresponds to the logic in the constructor of [VersionRange] with + // `alwaysIncludeMaxPreRelease = false` for discovering when a max-bound + // should not include prereleases. + + var max = range.max; + var min = range.min; + if (max == null) return null; if (range.includeMax) return null; - if (range.max.isPreRelease) return null; - if (range.min != null && - range.min.isPreRelease && - equalsIgnoringPreRelease(range.min, range.max)) { + if (max.isPreRelease) return null; + if (max.build.isNotEmpty) return null; + if (min != null && min.isPreRelease && equalsIgnoringPreRelease(min, max)) { return null; } - var index = _lowerBound(versions, range.max); + var index = _lowerBound(versions, max); var previous = index == 0 ? null : versions[index - 1].version; - return previous != null && equalsIgnoringPreRelease(previous, range.max) + return previous != null && equalsIgnoringPreRelease(previous, max) ? Pair(previous, true) - : Pair(range.max.firstPreRelease, false); + : Pair(max.firstPreRelease, false); } /// Returns the first index in [ids] (which is sorted by version) whose version
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart index 8bd3cc9..e3dd5dc 100644 --- a/lib/src/solver/report.dart +++ b/lib/src/solver/report.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub_semver/pub_semver.dart'; @@ -74,7 +72,7 @@ }).length; var suffix = ''; - if (_root.dir != null) { + if (!_root.isInMemory) { final dir = path.normalize(_root.dir); if (dir != '.') { suffix = ' in $dir'; @@ -91,7 +89,7 @@ } } else { if (numChanged == 0) { - if (_type == SolveType.GET) { + if (_type == SolveType.get) { log.message('Got dependencies$suffix!'); } else { log.message('No dependencies changed$suffix.'); @@ -153,7 +151,11 @@ if (id.source == null) continue; final status = await _cache.source(id.source).status(id, maxAge: Duration(days: 3)); - if (status.isDiscontinued) numDiscontinued++; + if (status.isDiscontinued && + (_root.dependencyType(id.name) == DependencyType.direct || + _root.dependencyType(id.name) == DependencyType.dev)) { + numDiscontinued++; + } } if (numDiscontinued > 0) { if (numDiscontinued == 1) { @@ -168,7 +170,7 @@ /// instruction to run `pub outdated` if outdated packages are detected. void reportOutdated() { final outdatedPackagesCount = _result.packages.where((id) { - final versions = _result.availableVersions[id.name]; + final versions = _result.availableVersions[id.name]!; // A version is counted: // - if there is a newer version which is not a pre-release and current // version is also not a pre-release or, @@ -199,7 +201,7 @@ {bool alwaysShow = false, bool highlightOverride = true}) async { var newId = _dependencies[name]; var oldId = _previousLockFile.packages[name]; - var id = newId ?? oldId; + var id = newId ?? oldId!; var isOverridden = _root.dependencyOverrides.containsKey(id.name); @@ -240,11 +242,11 @@ // Unchanged. icon = ' '; } - String message; + String? message; // See if there are any newer versions of the package that we were // unable to upgrade to. - if (newId != null && _type != SolveType.DOWNGRADE) { - var versions = _result.availableVersions[newId.name]; + if (newId != null && _type != SolveType.downgrade) { + var versions = _result.availableVersions[newId.name]!; var newerStable = false; var newerUnstable = false; @@ -270,7 +272,9 @@ } else { message = '(retracted)'; } - } else if (status.isDiscontinued) { + } else if (status.isDiscontinued && + (_root.dependencyType(name) == DependencyType.direct || + _root.dependencyType(name) == DependencyType.dev)) { if (status.discontinuedReplacedBy == null) { message = '(discontinued)'; } else { @@ -288,7 +292,7 @@ } } - if (_type == SolveType.GET && + if (_type == SolveType.get && !(alwaysShow || changed || addedOrRemoved || message != null)) { return; } @@ -301,7 +305,7 @@ // If the package was upgraded, show what it was upgraded from. if (changed) { _output.write(' (was '); - _writeId(oldId); + _writeId(oldId!); _output.write(')'); } @@ -320,7 +324,7 @@ _output.write(id.version); if (id.source != _sources.defaultSource) { - var description = id.source.formatDescription(id.description); + var description = id.source!.formatDescription(id.description); _output.write(' from ${id.source} $description'); } }
diff --git a/lib/src/solver/result.dart b/lib/src/solver/result.dart index ebcdfd7..bc01162 100644 --- a/lib/src/solver/result.dart +++ b/lib/src/solver/result.dart
@@ -2,15 +2,19 @@ // 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. -// @dart=2.10 - import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; +import '../http.dart'; +import '../io.dart'; import '../lock_file.dart'; +import '../log.dart' as log; import '../package.dart'; import '../package_name.dart'; +import '../pub_embeddable_command.dart'; import '../pubspec.dart'; +import '../source/cached.dart'; +import '../source/hosted.dart'; import '../source_registry.dart'; import '../system_cache.dart'; import 'report.dart'; @@ -44,6 +48,9 @@ /// because it found an invalid solution. final int attemptedSolutions; + /// The wall clock time the resolution took. + final Duration resolutionTime; + /// The [LockFile] representing the packages selected by this version /// resolution. LockFile get lockFile { @@ -73,12 +80,22 @@ final LockFile _previousLockFile; + /// Downloads all cached packages in [packages]. + Future<void> downloadCachedPackages(SystemCache cache) async { + await Future.wait(packages.map((id) async { + if (id.source == null) return; + final source = cache.source(id.source); + if (source is! CachedSource) return; + return await withDependencyType(_root.dependencyType(id.name), () async { + await source.downloadToSystemCache(id); + }); + })); + } + /// Returns the names of all packages that were changed. /// /// This includes packages that were added or removed. Set<String> get changedPackages { - if (packages == null) return null; - var changed = packages .where((id) => _previousLockFile.packages[id.name] != id) .map((id) => id.name) @@ -89,8 +106,15 @@ .toSet()); } - SolveResult(this._sources, this._root, this._previousLockFile, this.packages, - this.pubspecs, this.availableVersions, this.attemptedSolutions); + SolveResult( + this._sources, + this._root, + this._previousLockFile, + this.packages, + this.pubspecs, + this.availableVersions, + this.attemptedSolutions, + this.resolutionTime); /// Displays a report of what changes were made to the lockfile. /// @@ -112,12 +136,58 @@ final report = SolveReport(type, _sources, _root, _previousLockFile, this, cache); report.summarize(dryRun: dryRun); - if (type == SolveType.UPGRADE) { + if (type == SolveType.upgrade) { await report.reportDiscontinued(); report.reportOutdated(); } } + /// Send analytics about the package resolution. + void sendAnalytics(PubAnalytics pubAnalytics) { + ArgumentError.checkNotNull(pubAnalytics); + final analytics = pubAnalytics.analytics; + if (analytics == null) return; + + final dependenciesForAnalytics = <PackageId>[]; + for (final package in packages) { + // Only send analytics for packages from pub.dev. + if (HostedSource.isFromPubDev(package) || + (package.source is HostedSource && runningFromTest)) { + dependenciesForAnalytics.add(package); + } + } + // Randomize the dependencies, such that even if some analytics events don't + // get sent, the results will still be representative. + shuffle(dependenciesForAnalytics); + for (final package in dependenciesForAnalytics) { + final dependencyKind = const { + DependencyType.dev: 'dev', + DependencyType.direct: 'direct', + DependencyType.none: 'transitive' + }[_root.dependencyType(package.name)]!; + analytics.sendEvent( + 'pub-get', + package.name, + label: package.version.canonicalizedVersion, + value: 1, + parameters: { + 'ni': '1', // We consider a pub-get a non-interactive event. + pubAnalytics.dependencyKindCustomDimensionName: dependencyKind, + }, + ); + log.fine( + 'Sending analytics hit for "pub-get" of ${package.name} version ${package.version} as dependency-kind $dependencyKind'); + } + + analytics.sendTiming( + 'resolution', + resolutionTime.inMilliseconds, + category: 'pub-get', + ); + log.fine( + 'Sending analytics timing "pub-get" took ${resolutionTime.inMilliseconds} miliseconds'); + } + @override String toString() => 'Took $attemptedSolutions tries to resolve to\n' '- ${packages.join("\n- ")}';
diff --git a/lib/src/solver/set_relation.dart b/lib/src/solver/set_relation.dart index 09a1a80..2d88eb9 100644 --- a/lib/src/solver/set_relation.dart +++ b/lib/src/solver/set_relation.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - /// An enum of possible relationships between two sets. class SetRelation { /// The second set contains all elements of the first, as well as possibly
diff --git a/lib/src/solver/term.dart b/lib/src/solver/term.dart index f5f4662..266fabc 100644 --- a/lib/src/solver/term.dart +++ b/lib/src/solver/term.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub_semver/pub_semver.dart'; import '../package_name.dart'; @@ -60,7 +58,9 @@ if (otherConstraint.allowsAll(constraint)) return SetRelation.subset; // foo ^2.0.0 is disjoint with foo ^1.0.0 - if (!constraint.allowsAny(otherConstraint)) return SetRelation.disjoint; + if (!constraint.allowsAny(otherConstraint)) { + return SetRelation.disjoint; + } // foo >=1.5.0 <3.0.0 overlaps foo ^1.0.0 return SetRelation.overlapping; @@ -69,7 +69,9 @@ if (!_compatiblePackage(other.package)) return SetRelation.overlapping; // not foo ^1.0.0 is disjoint with foo ^1.5.0 - if (constraint.allowsAll(otherConstraint)) return SetRelation.disjoint; + if (constraint.allowsAll(otherConstraint)) { + return SetRelation.disjoint; + } // not foo ^1.5.0 overlaps foo ^1.0.0 // not foo ^2.0.0 is a superset of foo ^1.5.0 @@ -110,7 +112,7 @@ /// /// Throws an [ArgumentError] if [other] doesn't refer to a package with the /// same name as [package]. - Term intersect(Term other) { + Term? intersect(Term other) { if (package.name != other.package.name) { throw ArgumentError.value( other, 'other', 'should refer to package ${package.name}'); @@ -148,7 +150,7 @@ /// /// Throws an [ArgumentError] if [other] doesn't refer to a package with the /// same name as [package]. - Term difference(Term other) => intersect(other.inverse); // A ∖ B → A ∩ not B + Term? difference(Term other) => intersect(other.inverse); // A ∖ B → A ∩ not B /// Returns whether [other] is compatible with [package]. bool _compatiblePackage(PackageRange other) => @@ -157,7 +159,7 @@ /// Returns a new [Term] with the same package as [this] and with /// [constraint], unless that would produce a term that allows no packages, /// in which case this returns `null`. - Term _nonEmptyTerm(VersionConstraint constraint, bool isPositive) => + Term? _nonEmptyTerm(VersionConstraint constraint, bool isPositive) => constraint.isEmpty ? null : Term(package.withConstraint(constraint), isPositive);
diff --git a/lib/src/solver/type.dart b/lib/src/solver/type.dart index f0f37af..28a3230 100644 --- a/lib/src/solver/type.dart +++ b/lib/src/solver/type.dart
@@ -2,21 +2,19 @@ // 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. -// @dart=2.10 - /// An enum for types of version resolution. class SolveType { /// As few changes to the lockfile as possible to be consistent with the /// pubspec. - static const GET = SolveType._('get'); + static const get = SolveType._('get'); /// Upgrade all packages or specific packages to the highest versions /// possible, regardless of the lockfile. - static const UPGRADE = SolveType._('upgrade'); + static const upgrade = SolveType._('upgrade'); /// Downgrade all packages or specific packages to the lowest versions /// possible, regardless of the lockfile. - static const DOWNGRADE = SolveType._('downgrade'); + static const downgrade = SolveType._('downgrade'); final String _name;
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart index ee1541d..d4e3a75 100644 --- a/lib/src/solver/version_solver.dart +++ b/lib/src/solver/version_solver.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:math' as math; @@ -78,6 +76,8 @@ /// The set of packages for which the lockfile should be ignored. final Set<String> _unlock; + final _stopwatch = Stopwatch(); + VersionSolver(this._type, this._systemCache, this._root, this._lockFile, Iterable<String> unlock) : _dependencyOverrides = _root.pubspec.dependencyOverrides, @@ -86,14 +86,13 @@ /// Finds a set of dependencies that match the root package's constraints, or /// throws an error if no such set is available. Future<SolveResult> solve() async { - var stopwatch = Stopwatch()..start(); - + _stopwatch.start(); _addIncompatibility(Incompatibility( [Term(PackageRange.root(_root), false)], IncompatibilityCause.root)); try { return await _systemCache.hosted.withPrefetching(() async { - var next = _root.name; + String? next = _root.name; while (next != null) { _propagate(next); next = await _choosePackageVersion(); @@ -103,7 +102,7 @@ }); } finally { // Gather some solving metrics. - log.solver('Version solving took ${stopwatch.elapsed} seconds.\n' + log.solver('Version solving took ${_stopwatch.elapsed} seconds.\n' 'Tried ${_solution.attemptedSolutions} solutions.'); } } @@ -123,7 +122,7 @@ // general incompatibilities as time goes on. If we look at those first, // we can derive stronger assignments sooner and more eagerly find // conflicts. - for (var incompatibility in _incompatibilities[package].reversed) { + for (var incompatibility in _incompatibilities[package]!.reversed) { var result = _propagateIncompatibility(incompatibility); if (result == #conflict) { // If [incompatibility] is satisfied by [_solution], we use @@ -159,7 +158,7 @@ // The first entry in `incompatibility.terms` that's not yet satisfied by // [_solution], if one exists. If we find more than one, [_solution] is // inconclusive for [incompatibility] and we can't deduce anything. - Term unsatisfied; + Term? unsatisfied; for (var i = 0; i < incompatibility.terms.length; i++) { var term = incompatibility.terms[i]; @@ -208,17 +207,17 @@ while (!incompatibility.isFailure) { // The term in `incompatibility.terms` that was most recently satisfied by // [_solution]. - Term mostRecentTerm; + Term? mostRecentTerm; // The earliest assignment in [_solution] such that [incompatibility] is // satisfied by [_solution] up to and including this assignment. - Assignment mostRecentSatisfier; + Assignment? mostRecentSatisfier; // The difference between [mostRecentSatisfier] and [mostRecentTerm]; // that is, the versions that are allowed by [mostRecentSatisfier] and not // by [mostRecentTerm]. This is `null` if [mostRecentSatisfier] totally // satisfies [mostRecentTerm]. - Term difference; + Term? difference; // The decision level of the earliest assignment in [_solution] *before* // [mostRecentSatisfier] such that [incompatibility] is satisfied by @@ -251,7 +250,7 @@ // If [mostRecentSatisfier] doesn't satisfy [mostRecentTerm] on its // own, then the next-most-recent satisfier may be the one that // satisfies the remainder. - difference = mostRecentSatisfier.difference(mostRecentTerm); + difference = mostRecentSatisfier.difference(mostRecentTerm!); if (difference != null) { previousSatisfierLevel = math.max(previousSatisfierLevel, _solution.satisfier(difference.inverse).decisionLevel); @@ -264,7 +263,7 @@ // than a derivation), then [incompatibility] is the root cause. We then // backjump to [previousSatisfierLevel], where [incompatibility] is // guaranteed to allow [_propagate] to produce more assignments. - if (previousSatisfierLevel < mostRecentSatisfier.decisionLevel || + if (previousSatisfierLevel < mostRecentSatisfier!.decisionLevel || mostRecentSatisfier.cause == null) { _solution.backtrack(previousSatisfierLevel); if (newIncompatibility) _addIncompatibility(incompatibility); @@ -280,7 +279,7 @@ var newTerms = <Term>[ for (var term in incompatibility.terms) if (term != mostRecentTerm) term, - for (var term in mostRecentSatisfier.cause.terms) + for (var term in mostRecentSatisfier.cause!.terms) if (term.package != mostRecentSatisfier.package) term, ]; @@ -299,7 +298,7 @@ if (difference != null) newTerms.add(difference.inverse); incompatibility = Incompatibility( - newTerms, ConflictCause(incompatibility, mostRecentSatisfier.cause)); + newTerms, ConflictCause(incompatibility, mostRecentSatisfier.cause!)); newIncompatibility = true; var partially = difference == null ? '' : ' partially'; @@ -318,7 +317,7 @@ /// Returns the name of the package whose incompatibilities should be /// propagated by [_propagate], or `null` indicating that version solving is /// complete and a solution has been found. - Future<String> _choosePackageVersion() async { + Future<String?> _choosePackageVersion() async { var unsatisfied = _solution.unsatisfied.toList(); if (unsatisfied.isEmpty) return null; @@ -334,14 +333,14 @@ /// Prefer packages with as few remaining versions as possible, so that if a /// conflict is necessary it's forced quickly. - var package = await minByAsync(unsatisfied, (package) async { + var package = await minByAsync(unsatisfied, (PackageRange package) async { return await _packageLister(package).countVersions(package.constraint); }); if (package == null) { return null; // when unsatisfied.isEmpty } - PackageId version; + PackageId? version; try { version = await _packageLister(package).bestVersion(package.constraint); } on PackageNotFoundException catch (error) { @@ -370,7 +369,7 @@ var conflict = false; for (var incompatibility - in await _packageLister(package).incompatibilitiesFor(version)) { + in await _packageLister(package).incompatibilitiesFor(version!)) { _addIncompatibility(incompatibility); // If an incompatibility is already satisfied, then selecting [version] @@ -418,13 +417,15 @@ } return SolveResult( - _systemCache.sources, - _root, - _lockFile, - decisions, - pubspecs, - await _getAvailableVersions(decisions), - _solution.attemptedSolutions); + _systemCache.sources, + _root, + _lockFile, + decisions, + pubspecs, + await _getAvailableVersions(decisions), + _solution.attemptedSolutions, + _stopwatch.elapsed, + ); } /// Generates a map containing all of the known available versions for each @@ -484,15 +485,15 @@ _root.dependencyType(package.name), overridden, _getAllowedRetracted(ref.name), - downgrade: _type == SolveType.DOWNGRADE); + downgrade: _type == SolveType.downgrade); }); } /// Gets the version of [package] currently locked in the lock file. /// /// Returns `null` if it isn't in the lockfile (or has been unlocked). - PackageId _getLocked(String package) { - if (_type == SolveType.GET) { + PackageId? _getLocked(String? package) { + if (_type == SolveType.get) { if (_unlock.contains(package)) { return null; } @@ -502,9 +503,9 @@ // When downgrading, we don't want to force the latest versions of // non-hosted packages, since they don't support multiple versions and thus // can't be downgraded. - if (_type == SolveType.DOWNGRADE) { + if (_type == SolveType.downgrade) { var locked = _lockFile.packages[package]; - if (locked != null && !locked.source.hasMultipleVersions) return locked; + if (locked != null && !locked.source!.hasMultipleVersions) return locked; } if (_unlock.isEmpty || _unlock.contains(package)) return null; @@ -512,16 +513,17 @@ } /// Gets the version of [package] which can be allowed during version solving - /// even if that version is marked as retracted. + /// even if that version is marked as retracted. Returns `null` if no such + /// version exists. /// /// We only allow resolving to a retracted version if it is already in the /// `pubspec.lock` or pinned in `dependency_overrides`. - Version _getAllowedRetracted(String package) { + Version? _getAllowedRetracted(String? package) { if (_dependencyOverrides.containsKey(package)) { - var range = _dependencyOverrides[package]; + var range = _dependencyOverrides[package]!; if (range.constraint is Version) { // We have a pinned dependency. - return range.constraint; + return range.constraint as Version?; } } return _lockFile.packages[package]?.version; @@ -530,7 +532,7 @@ /// Logs [message] in the context of the current selected packages. /// /// If [message] is omitted, just logs a description of leaf-most selection. - void _log([String message]) { + void _log([String message = '']) { // Indent for the previous selections. log.solver(prefixLines(message, prefix: ' ' * _solution.decisionLevel)); }
diff --git a/lib/src/source.dart b/lib/src/source.dart index 4fe2322..ecbc5eb 100644 --- a/lib/src/source.dart +++ b/lib/src/source.dart
@@ -2,13 +2,13 @@ // 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. -// @dart=2.10 - import 'dart:async'; +import 'package:collection/collection.dart' show IterableNullableExtension; import 'package:pub_semver/pub_semver.dart'; import 'exceptions.dart'; +import 'language_version.dart'; import 'package_name.dart'; import 'pubspec.dart'; import 'system_cache.dart'; @@ -77,16 +77,27 @@ /// should be interpreted. This will be called during parsing to validate that /// the given [description] is well-formed according to this source, and to /// give the source a chance to canonicalize the description. + /// For simple hosted dependencies like `foo:` or `foo: ^1.2.3`, the + /// [description] may also be `null`. /// /// [containingPath] is the path to the pubspec where this description /// appears. It may be `null` if the description is coming from some in-memory /// source (such as pulling down a pubspec from pub.dartlang.org). /// + /// [languageVersion] is the minimum Dart version parsed from the pubspec's + /// `environment` field. Source implementations may use this parameter to only + /// support specific syntax for some versions. + /// /// The description in the returned [PackageRef] need bear no resemblance to /// the original user-provided description. /// /// Throws a [FormatException] if the description is not valid. - PackageRef parseRef(String name, description, {String containingPath}); + PackageRef parseRef( + String name, + description, { + String? containingPath, + required LanguageVersion languageVersion, + }); /// Parses a [PackageId] from a name and a serialized description. /// @@ -99,13 +110,13 @@ /// /// Throws a [FormatException] if the description is not valid. PackageId parseId(String name, Version version, description, - {String containingPath}); + {String? containingPath}); /// When a [LockFile] is serialized, it uses this method to get the /// [description] in the right format. /// /// [containingPath] is the containing directory of the root package. - dynamic serializeDescription(String containingPath, description) { + dynamic serializeDescription(String? containingPath, description) { return description; } @@ -166,7 +177,7 @@ /// selected even if it is marked as retracted. Otherwise, all the returned /// IDs correspond to non-retracted versions. Future<List<PackageId>> getVersions(PackageRef ref, - {Duration maxAge, Version allowedRetractedVersion}) async { + {Duration? maxAge, Version? allowedRetractedVersion}) async { if (ref.isRoot) { throw ArgumentError('Cannot get versions for the root package.'); } @@ -183,7 +194,7 @@ } return null; }))) - .where((element) => element != null) + .whereNotNull() .toList(); return versions; @@ -201,7 +212,7 @@ /// /// This method is effectively protected: subclasses must implement it, but /// external code should not call this. Instead, call [getVersions]. - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge); + Future<List<PackageId>> doGetVersions(PackageRef ref, Duration? maxAge); /// A cache of pubspecs described by [describe]. final _pubspecs = <PackageId, Pubspec>{}; @@ -256,7 +267,7 @@ /// /// If id is a relative path id, the directory will be relative from /// [relativeFrom]. Returns an absolute path if [relativeFrom] is not passed. - String getDirectory(PackageId id, {String relativeFrom}); + String getDirectory(PackageId id, {String? relativeFrom}); /// Returns metadata about a given package. /// @@ -265,7 +276,7 @@ /// /// In the case of offline sources, [maxAge] is not used, since information is /// per definiton cached. - Future<PackageStatus> status(PackageId id, {Duration maxAge}) async => + Future<PackageStatus> status(PackageId id, {Duration? maxAge}) async => // Default implementation has no metadata. PackageStatus(); @@ -282,10 +293,11 @@ /// `null` if not [isDiscontinued]. Otherwise contains the /// replacement string provided by the host or `null` if there is no /// replacement. - final String discontinuedReplacedBy; + final String? discontinuedReplacedBy; final bool isDiscontinued; final bool isRetracted; - PackageStatus({isDiscontinued, this.discontinuedReplacedBy, isRetracted}) - : isDiscontinued = isDiscontinued ?? false, - isRetracted = isRetracted ?? false; + PackageStatus( + {this.isDiscontinued = false, + this.discontinuedReplacedBy, + this.isRetracted = false}); }
diff --git a/lib/src/source/cached.dart b/lib/src/source/cached.dart index c0d9ef1..0c8574d 100644 --- a/lib/src/source/cached.dart +++ b/lib/src/source/cached.dart
@@ -2,11 +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. -// @dart=2.10 - import 'dart:async'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import '../io.dart'; @@ -43,7 +40,7 @@ } @override - String getDirectory(PackageId id, {String relativeFrom}) => + String getDirectory(PackageId id, {String? relativeFrom}) => getDirectoryInCache(id); String getDirectoryInCache(PackageId id); @@ -82,5 +79,5 @@ /// cache (but that might itself have failed). final bool success; final PackageId package; - RepairResult(this.package, {@required this.success}); + RepairResult(this.package, {required this.success}); }
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart index 5f1def9..3be752c 100644 --- a/lib/src/source/git.dart +++ b/lib/src/source/git.dart
@@ -2,17 +2,17 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; +import 'package:collection/collection.dart' show IterableNullableExtension; import 'package:path/path.dart' as p; import 'package:pool/pool.dart'; import 'package:pub_semver/pub_semver.dart'; import '../git.dart' as git; import '../io.dart'; +import '../language_version.dart'; import '../log.dart' as log; import '../package.dart'; import '../package_name.dart'; @@ -44,7 +44,12 @@ } @override - PackageRef parseRef(String name, description, {String containingPath}) { + PackageRef parseRef( + String name, + description, { + String? containingPath, + LanguageVersion? languageVersion, + }) { dynamic url; dynamic ref; dynamic path; @@ -73,7 +78,7 @@ @override PackageId parseId(String name, Version version, description, - {String containingPath}) { + {String? containingPath}) { if (description is! Map) { throw FormatException("The description must be a map with a 'url' " 'key.'); @@ -103,10 +108,10 @@ /// For the descriptions where `relative` attribute is `true`, tries to make /// `url` relative to the specified [containingPath]. @override - dynamic serializeDescription(String containingPath, description) { + dynamic serializeDescription(String? containingPath, description) { final copy = Map.from(description); copy.remove('relative'); - if (description['relative'] == true) { + if (description['relative'] == true && containingPath != null) { copy['url'] = p.url.relative(description['url'], from: Uri.file(containingPath).toString()); } @@ -114,7 +119,7 @@ } /// Throws a [FormatException] if [url] isn't a valid Git URL. - Map<String, Object> _validatedUrl(dynamic url, String containingDir) { + Map<String, Object> _validatedUrl(dynamic url, String? containingDir) { if (url is! String) { throw FormatException("The 'url' field of the description must be a " 'string.'); @@ -248,7 +253,8 @@ } @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async { + Future<List<PackageId>> doGetVersions( + PackageRef ref, Duration? maxAge) async { return await _pool.withResource(() async { await _ensureRepoCache(ref); var path = _repoCachePath(ref); @@ -301,7 +307,7 @@ // Git doesn't recognize backslashes in paths, even on Windows. if (Platform.isWindows) pubspecPath = pubspecPath.replaceAll('\\', '/'); - List<String> lines; + late List<String> lines; try { lines = await git .run(['show', '$revision:$pubspecPath'], workingDir: repoPath); @@ -361,8 +367,8 @@ /// Returns the path to the revision-specific cache of [id]. @override - String getDirectoryInCache(PackageId id) => - p.join(_revisionCachePath(id), id.description['path']); + String getDirectoryInCache(PackageId? id) => + p.join(_revisionCachePath(id!), id.description['path']); @override List<Package> getCachedPackages() { @@ -401,7 +407,7 @@ } }); }) - .where((package) => package != null) + .whereNotNull() .toList(); // Note that there may be multiple packages with the same name and version @@ -516,7 +522,7 @@ ['rev-parse', '--is-inside-git-dir'], workingDir: dirPath, ); - if (result?.join('\n') != 'true') { + if (result.join('\n') != 'true') { isValid = false; } } on git.GitException {
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart index 11f37b8..2cfc52a 100644 --- a/lib/src/source/hosted.dart +++ b/lib/src/source/hosted.dart
@@ -2,16 +2,14 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io' as io; -import 'package:collection/collection.dart' show maxBy; +import 'package:collection/collection.dart' + show maxBy, IterableNullableExtension; import 'package:http/http.dart' as http; import 'package:path/path.dart' as p; -import 'package:pedantic/pedantic.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -19,6 +17,7 @@ import '../exceptions.dart'; import '../http.dart'; import '../io.dart'; +import '../language_version.dart'; import '../log.dart' as log; import '../package.dart'; import '../package_name.dart'; @@ -97,6 +96,13 @@ ? _OfflineHostedSource(this, systemCache) : BoundHostedSource(this, systemCache); + static String pubDevUrl = 'https://pub.dartlang.org'; + + static bool isFromPubDev(PackageId id) { + return id.source is HostedSource && + (id.description as _HostedDescription).uri.toString() == pubDevUrl; + } + /// Gets the default URL for the package server for hosted dependencies. Uri get defaultUrl { // Changing this to pub.dev raises the following concerns: @@ -120,27 +126,27 @@ } } - Uri _defaultUrl; + Uri? _defaultUrl; /// Returns a reference to a hosted package named [name]. /// /// If [url] is passed, it's the URL of the pub server from which the package /// should be downloaded. [url] most be normalized and validated using /// [validateAndNormalizeHostedUrl]. - PackageRef refFor(String name, {Uri url}) => - PackageRef(name, this, _descriptionFor(name, url)); + PackageRef refFor(String name, {Uri? url}) => + PackageRef(name, this, _HostedDescription(name, url ?? defaultUrl)); /// Returns an ID for a hosted package named [name] at [version]. /// /// If [url] is passed, it's the URL of the pub server from which the package /// should be downloaded. [url] most be normalized and validated using /// [validateAndNormalizeHostedUrl]. - PackageId idFor(String name, Version version, {Uri url}) => - PackageId(name, this, version, _descriptionFor(name, url)); + PackageId idFor(String name, Version version, {Uri? url}) => PackageId( + name, this, version, _HostedDescription(name, url ?? defaultUrl)); /// Returns the description for a hosted package named [name] with the /// given package server [url]. - dynamic _descriptionFor(String name, [Uri url]) { + dynamic _serializedDescriptionFor(String name, [Uri? url]) { if (url == null) { return name; } @@ -153,54 +159,118 @@ } @override + dynamic serializeDescription(String? containingPath, description) { + final desc = _asDescription(description); + return _serializedDescriptionFor(desc.packageName, desc.uri); + } + + @override String formatDescription(description) => - 'on ${_parseDescription(description).last}'; + 'on ${_asDescription(description).uri}'; @override bool descriptionsEqual(description1, description2) => - _parseDescription(description1) == _parseDescription(description2); + _asDescription(description1) == _asDescription(description2); @override - int hashDescription(description) => _parseDescription(description).hashCode; + int hashDescription(description) => _asDescription(description).hashCode; /// Ensures that [description] is a valid hosted package description. /// - /// There are two valid formats. A plain string refers to a package with the - /// given name from the default host, while a map with keys "name" and "url" - /// refers to a package with the given name from the host at the given URL. + /// Simple hosted dependencies only consist of a plain string, which is + /// resolved against the default host. In this case, [description] will be + /// null. + /// + /// Hosted dependencies may also specify a custom host from which the package + /// is fetched. There are two syntactic forms of those dependencies: + /// + /// 1. With an url and an optional name in a map: `hosted: {url: <url>}` + /// 2. With a direct url: `hosted: <url>` @override - PackageRef parseRef(String name, description, {String containingPath}) { - _parseDescription(description); - return PackageRef(name, this, description); + PackageRef parseRef(String name, description, + {String? containingPath, required LanguageVersion languageVersion}) { + return PackageRef( + name, this, _parseDescription(name, description, languageVersion)); } @override PackageId parseId(String name, Version version, description, - {String containingPath}) { - _parseDescription(description); - return PackageId(name, this, version, description); + {String? containingPath}) { + // Old pub versions only wrote `description: <pkg>` into the lock file. + if (description is String) { + if (description != name) { + throw FormatException('The description should be the same as the name'); + } + return PackageId( + name, this, version, _HostedDescription(name, defaultUrl)); + } + + final serializedDescription = (description as Map).cast<String, String>(); + + return PackageId( + name, + this, + version, + _HostedDescription(serializedDescription['name']!, + Uri.parse(serializedDescription['url']!)), + ); } + _HostedDescription _asDescription(desc) => desc as _HostedDescription; + /// Parses the description for a package. /// /// If the package parses correctly, this returns a (name, url) pair. If not, /// this throws a descriptive FormatException. - Pair<String, Uri> _parseDescription(description) { + _HostedDescription _parseDescription( + String packageName, + description, + LanguageVersion languageVersion, + ) { + if (description == null) { + // Simple dependency without a `hosted` block, use the default server. + return _HostedDescription(packageName, defaultUrl); + } + + final canUseShorthandSyntax = languageVersion.supportsShorterHostedSyntax; + if (description is String) { - return Pair<String, Uri>(description, defaultUrl); + // Old versions of pub (pre Dart 2.15) interpret `hosted: foo` as + // `hosted: {name: foo, url: <default>}`. + // For later versions, we treat it as `hosted: {name: <inferred>, + // url: foo}` if a user opts in by raising their min SDK environment. + // + // Since the old behavior is very rarely used and we want to show a + // helpful error message if the new syntax is used without raising the SDK + // environment, we throw an error if something that looks like a URI is + // used as a package name. + if (canUseShorthandSyntax) { + return _HostedDescription( + packageName, validateAndNormalizeHostedUrl(description)); + } else { + if (_looksLikePackageName.hasMatch(description)) { + // Valid use of `hosted: package` dependency with an old SDK + // environment. + return _HostedDescription(description, defaultUrl); + } else { + throw FormatException( + 'Using `hosted: <url>` is only supported with a minimum SDK ' + 'constraint of ${LanguageVersion.firstVersionWithShorterHostedSyntax}.', + ); + } + } } if (description is! Map) { throw FormatException('The description must be a package name or map.'); } - if (!description.containsKey('name')) { - throw FormatException("The description map must contain a 'name' key."); - } - var name = description['name']; + if (canUseShorthandSyntax) name ??= packageName; + if (name is! String) { - throw FormatException("The 'name' key must have a string value."); + throw FormatException("The 'name' key must have a string value without " + 'a minimum Dart SDK constraint of ${LanguageVersion.firstVersionWithShorterHostedSyntax}.0 or higher.'); } var url = defaultUrl; @@ -212,8 +282,11 @@ url = validateAndNormalizeHostedUrl(u); } - return Pair<String, Uri>(name, url); + return _HostedDescription(name, url); } + + static final RegExp _looksLikePackageName = + RegExp(r'^[a-zA-Z_]+[a-zA-Z0-9_]*$'); } /// Information about a package version retrieved from /api/packages/$package @@ -225,6 +298,28 @@ _VersionInfo(this.pubspec, this.archiveUrl, this.status); } +/// The [PackageName.description] for a [HostedSource], storing the package name +/// and resolved URI of the package server. +class _HostedDescription { + final String packageName; + final Uri uri; + + _HostedDescription(this.packageName, this.uri) { + ArgumentError.checkNotNull(packageName, 'packageName'); + ArgumentError.checkNotNull(uri, 'uri'); + } + + @override + int get hashCode => Object.hash(packageName, uri); + + @override + bool operator ==(Object other) { + return other is _HostedDescription && + other.packageName == packageName && + other.uri == uri; + } +} + /// The [BoundSource] for [HostedSource]. class BoundHostedSource extends CachedSource { @override @@ -232,7 +327,8 @@ @override final SystemCache systemCache; - RateLimitedScheduler<PackageRef, Map<PackageId, _VersionInfo>> _scheduler; + late RateLimitedScheduler<PackageRef, Map<PackageId, _VersionInfo>?> + _scheduler; BoundHostedSource(this.source, this.systemCache) { _scheduler = RateLimitedScheduler( @@ -255,9 +351,9 @@ var archiveUrl = map['archive_url']; if (archiveUrl is String) { final status = PackageStatus( - isDiscontinued: body['isDiscontinued'] as bool ?? false, - discontinuedReplacedBy: body['replacedBy'] as String, - isRetracted: map['retracted'] as bool ?? false); + isDiscontinued: body['isDiscontinued'] ?? false, + discontinuedReplacedBy: body['replacedBy'], + isRetracted: map['retracted'] ?? false); return MapEntry( id, _VersionInfo(pubspec, Uri.parse(archiveUrl), status)); } @@ -269,15 +365,15 @@ throw FormatException('versions must be a list'); } - Future<Map<PackageId, _VersionInfo>> _fetchVersionsNoPrefetching( + Future<Map<PackageId, _VersionInfo>?> _fetchVersionsNoPrefetching( PackageRef ref) async { final serverUrl = _hostedUrl(ref.description); final url = _listVersionsUrl(ref.description); log.io('Get versions from $url.'); - String bodyText; - Map body; - Map<PackageId, _VersionInfo> result; + late final String bodyText; + late final dynamic body; + late final Map<PackageId, _VersionInfo> result; try { // TODO(sigurdm): Implement cancellation of requests. This probably // requires resolution of: https://github.com/dart-lang/sdk/issues/22265. @@ -286,39 +382,44 @@ serverUrl, (client) => client.read(url, headers: pubApiHeaders), ); - body = jsonDecode(bodyText); + final decoded = jsonDecode(bodyText); + if (decoded is! Map<String, dynamic>) { + throw FormatException('version listing must be a mapping'); + } + body = decoded; result = _versionInfoFromPackageListing(body, ref, url); - } catch (error, stackTrace) { - var parsed = source._parseDescription(ref.description); - _throwFriendlyError(error, stackTrace, parsed.first, parsed.last); + } on Exception catch (error, stackTrace) { + final packageName = source._asDescription(ref.description).packageName; + _throwFriendlyError(error, stackTrace, packageName, serverUrl); } // Cache the response on disk. // Don't cache overly big responses. - if (body.length < 100 * 1024) { + if (bodyText.length < 100 * 1024) { await _cacheVersionListingResponse(body, ref); } return result; } - Future<Map<PackageId, _VersionInfo>> _fetchVersions(PackageRef ref) async { + Future<Map<PackageId, _VersionInfo>?> _fetchVersions(PackageRef ref) async { final preschedule = - Zone.current[_prefetchingKey] as void Function(PackageRef); + Zone.current[_prefetchingKey] as void Function(PackageRef)?; /// Prefetch the dependencies of the latest version, we are likely to need /// them later. - void prescheduleDependenciesOfLatest(Map<PackageId, _VersionInfo> listing) { + void prescheduleDependenciesOfLatest( + Map<PackageId, _VersionInfo>? listing) { if (listing == null) return; final latestVersion = - maxBy(listing.keys.map((id) => id.version), (e) => e); + maxBy(listing.keys.map((id) => id.version), (e) => e)!; final latestVersionId = PackageId(ref.name, source, latestVersion, ref.description); final dependencies = - listing[latestVersionId]?.pubspec?.dependencies?.values ?? []; + listing[latestVersionId]?.pubspec.dependencies.values ?? []; unawaited(withDependencyType(DependencyType.none, () async { for (final packageRange in dependencies) { if (packageRange.source is HostedSource) { - preschedule(packageRange.toRef()); + preschedule!(packageRange.toRef()); } } })); @@ -341,6 +442,15 @@ return result; } + /// An in-memory cache to store the cached version listing loaded from + /// [_versionListingCachePath]. + /// + /// Invariant: Entries in this cache are the parsed version of the exact same + /// information cached on disk. I.e. if the entry is present in this cache, + /// there will not be a newer version on disk. + final Map<PackageRef, Pair<DateTime, Map<PackageId, _VersionInfo>>> + _responseCache = {}; + /// If a cached version listing response for [ref] exists on disk and is less /// than [maxAge] old it is parsed and returned. /// @@ -348,29 +458,38 @@ /// /// If [maxAge] is not given, we will try to get the cached version no matter /// how old it is. - Future<Map<PackageId, _VersionInfo>> _cachedVersionListingResponse( + Future<Map<PackageId, _VersionInfo>?> _cachedVersionListingResponse( PackageRef ref, - {Duration maxAge}) async { + {Duration? maxAge}) async { + if (_responseCache.containsKey(ref)) { + final cacheAge = DateTime.now().difference(_responseCache[ref]!.first); + if (maxAge == null || maxAge > cacheAge) { + // The cached value is not too old. + return _responseCache[ref]!.last; + } + } final cachePath = _versionListingCachePath(ref); - final stat = await io.File(cachePath).stat(); + final stat = io.File(cachePath).statSync(); final now = DateTime.now(); if (stat.type == io.FileSystemEntityType.file) { if (maxAge == null || now.difference(stat.modified) < maxAge) { try { - final cachedDoc = jsonDecode(await readTextFileAsync(cachePath)); + final cachedDoc = jsonDecode(readTextFile(cachePath)); final timestamp = cachedDoc['_fetchedAt']; if (timestamp is String) { - final cacheAge = - DateTime.now().difference(DateTime.parse(timestamp)); + final parsedTimestamp = DateTime.parse(timestamp); + final cacheAge = DateTime.now().difference(parsedTimestamp); if (maxAge != null && cacheAge > maxAge) { // Too old according to internal timestamp - delete. tryDeleteEntry(cachePath); } else { - return _versionInfoFromPackageListing( + var res = _versionInfoFromPackageListing( cachedDoc, ref, Uri.file(cachePath), ); + _responseCache[ref] = Pair(parsedTimestamp, res); + return res; } } } on io.IOException { @@ -389,7 +508,8 @@ } /// Saves the (decoded) response from package-listing of [ref]. - Future<void> _cacheVersionListingResponse(Map body, PackageRef ref) async { + Future<void> _cacheVersionListingResponse( + Map<String, dynamic> body, PackageRef ref) async { final path = _versionListingCachePath(ref); try { ensureDir(p.dirname(path)); @@ -402,6 +522,9 @@ }, ), ); + // Delete the entry in the in-memory cache to maintain the invariant that + // cached information in memory is the same as that on the disk. + _responseCache.remove(ref); } on io.IOException catch (e) { // Not being able to write this cache is not fatal. Just move on... log.fine('Failed writing cache file. $e'); @@ -409,7 +532,7 @@ } @override - Future<PackageStatus> status(PackageId id, {Duration maxAge}) async { + Future<PackageStatus> status(PackageId id, {Duration? maxAge}) async { final ref = id.toRef(); // Did we already get info for this package? var versionListing = _scheduler.peek(ref); @@ -427,7 +550,7 @@ test: (error) => error is Exception, ); - final listing = versionListing[id]; + final listing = versionListing![id]; // If we don't have the specific version we return the empty response, since // it is more or less harmless.. // @@ -441,8 +564,8 @@ // The path where the response from the package-listing api is cached. String _versionListingCachePath(PackageRef ref) { - final parsed = source._parseDescription(ref.description); - final dir = _urlToDirectory(parsed.last); + final parsed = source._asDescription(ref.description); + final dir = _urlToDirectory(parsed.uri); // Use a dot-dir because older versions of pub won't choke on that // name when iterating the cache (it is not listed by [listDir]). return p.join(systemCacheRoot, dir, _versionListingDirectory, @@ -454,7 +577,8 @@ /// Downloads a list of all versions of a package that are available from the /// site. @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async { + Future<List<PackageId>> doGetVersions( + PackageRef ref, Duration? maxAge) async { var versionListing = _scheduler.peek(ref); if (maxAge != null) { // Do we have a cached version response on disk? @@ -462,22 +586,22 @@ await _cachedVersionListingResponse(ref, maxAge: maxAge); } versionListing ??= await _scheduler.schedule(ref); - return versionListing.keys.toList(); + return versionListing!.keys.toList(); } /// Parses [description] into its server and package name components, then /// converts that to a Uri for listing versions of the given package. Uri _listVersionsUrl(description) { - final parsed = source._parseDescription(description); - final hostedUrl = parsed.last; - final package = Uri.encodeComponent(parsed.first); + final parsed = source._asDescription(description); + final hostedUrl = parsed.uri; + final package = Uri.encodeComponent(parsed.packageName); return hostedUrl.resolve('api/packages/$package'); } /// Parses [description] into server name component. Uri _hostedUrl(description) { - final parsed = source._parseDescription(description); - return parsed.last; + final parsed = source._asDescription(description); + return parsed.uri; } /// Retrieves the pubspec for a specific version of a package that is @@ -486,7 +610,7 @@ Future<Pubspec> describeUncached(PackageId id) async { final versions = await _scheduler.schedule(id.toRef()); final url = _listVersionsUrl(id.description); - return versions[id]?.pubspec ?? + return versions![id]?.pubspec ?? (throw PackageNotFoundException('Could not find package $id at $url')); } @@ -509,9 +633,9 @@ /// package downloaded from that site. @override String getDirectoryInCache(PackageId id) { - var parsed = source._parseDescription(id.description); - var dir = _urlToDirectory(parsed.last); - return p.join(systemCacheRoot, dir, '${parsed.first}-${id.version}'); + var parsed = source._asDescription(id.description); + var dir = _urlToDirectory(parsed.uri); + return p.join(systemCacheRoot, dir, '${parsed.packageName}-${id.version}'); } /// Re-downloads all packages that have been previously downloaded into the @@ -564,6 +688,7 @@ packages.map((package) async { var id = source.idFor(package.name, package.version, url: url); try { + deleteEntry(package.dir); await _download(id, package.dir); return RepairResult(id, success: true); } catch (error, stackTrace) { @@ -584,7 +709,7 @@ /// Returns the best-guess package ID for [basename], which should be a /// subdirectory in a hosted cache. - PackageId _idForBasename(String basename, {Uri url}) { + PackageId _idForBasename(String basename, {Uri? url}) { var components = split1(basename, '-'); var version = Version.none; if (components.length > 1) { @@ -621,7 +746,7 @@ return null; } }) - .where((e) => e != null) + .whereNotNull() .toList(); } @@ -642,20 +767,17 @@ // query-string as is the case with signed S3 URLs. And we wish to allow for // such URLs to be used. final versions = await _scheduler.schedule(id.toRef()); - final versionInfo = versions[id]; + final versionInfo = versions![id]; final packageName = id.name; final version = id.version; if (versionInfo == null) { throw PackageNotFoundException( 'Package $packageName has no version $version'); } - final parsedDescription = source._parseDescription(id.description); - final server = parsedDescription.last; + final parsedDescription = source._asDescription(id.description); + final server = parsedDescription.uri; var url = versionInfo.archiveUrl; - // To support old servers that has no archive_url we fall back to the - // hard-coded path. - url ??= Uri.parse('$server/packages/$packageName/versions/$version.tar.gz'); log.io('Get package from $url.'); log.message('Downloading ${log.bold(id.name)} ${id.version}...'); @@ -675,51 +797,74 @@ var tempDir = systemCache.createTempDir(); await extractTarGz(readBinaryFileAsSream(archivePath), tempDir); - // Remove the existing directory if it exists. This will happen if - // we're forcing a download to repair the cache. - if (dirExists(destPath)) deleteEntry(destPath); - // Now that the get has succeeded, move it to the real location in the - // cache. This ensures that we don't leave half-busted ghost - // directories in the user's pub cache if a get fails. - renameDir(tempDir, destPath); + // cache. + // + // If this fails with a "directory not empty" exception we assume that + // another pub process has installed the same package version while we + // downloaded. + tryRenameDir(tempDir, destPath); }); } - /// When an error occurs trying to read something about [package] from [url], + /// When an error occurs trying to read something about [package] from [hostedUrl], /// this tries to translate into a more user friendly error message. /// /// Always throws an error, either the original one or a better one. - void _throwFriendlyError( - error, + Never _throwFriendlyError( + Exception error, StackTrace stackTrace, String package, - Uri url, + Uri hostedUrl, ) { if (error is PubHttpException) { if (error.response.statusCode == 404) { throw PackageNotFoundException( - 'could not find package $package at $url', + 'could not find package $package at $hostedUrl', innerError: error, innerTrace: stackTrace); } fail( '${error.response.statusCode} ${error.response.reasonPhrase} trying ' - 'to find package $package at $url.', + 'to find package $package at $hostedUrl.', error, stackTrace); } else if (error is io.SocketException) { - fail('Got socket error trying to find package $package at $url.', error, - stackTrace); + fail('Got socket error trying to find package $package at $hostedUrl.', + error, stackTrace); } else if (error is io.TlsException) { - fail('Got TLS error trying to find package $package at $url.', error, - stackTrace); + fail('Got TLS error trying to find package $package at $hostedUrl.', + error, stackTrace); + } else if (error is AuthenticationException) { + String? hint; + var message = 'authentication failed'; + + assert(error.statusCode == 401 || error.statusCode == 403); + if (error.statusCode == 401) { + hint = '$hostedUrl package repository requested authentication!\n' + 'You can provide credentials using:\n' + ' pub token add $hostedUrl'; + } + if (error.statusCode == 403) { + hint = 'Insufficient permissions to the resource at the $hostedUrl ' + 'package repository.\nYou can modify credentials using:\n' + ' pub token add $hostedUrl'; + message = 'authorization failed'; + } + + if (error.serverMessage?.isNotEmpty == true && hint != null) { + hint += '\n${error.serverMessage}'; + } + + throw PackageNotFoundException(message, hint: hint); } else if (error is FormatException) { throw PackageNotFoundException( - 'Got badly formatted response trying to find package $package at $url', - innerError: error, - innerTrace: stackTrace); + 'Got badly formatted response trying to find package $package at $hostedUrl', + innerError: error, + innerTrace: stackTrace, + hint: 'Check that "$hostedUrl" is a valid package repository.', + ); } else { // Otherwise re-throw the original exception. throw error; @@ -755,7 +900,7 @@ return replace( url, RegExp(r'[<>:"\\/|?*%]'), - (match) => '%${match[0].codeUnitAt(0)}', + (match) => '%${match[0]!.codeUnitAt(0)}', ); } @@ -786,7 +931,7 @@ } /// Returns the server URL for [description]. - Uri _serverFor(description) => source._parseDescription(description).last; + Uri _serverFor(description) => source._asDescription(description).uri; /// Enables speculative prefetching of dependencies of packages queried with /// [getVersions]. @@ -812,9 +957,12 @@ /// Gets the list of all versions of [ref] that are in the system cache. @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async { - var parsed = source._parseDescription(ref.description); - var server = parsed.last; + Future<List<PackageId>> doGetVersions( + PackageRef ref, + Duration? maxAge, + ) async { + var parsed = source._asDescription(ref.description); + var server = parsed.uri; log.io('Finding versions of ${ref.name} in ' '$systemCacheRoot/${_urlToDirectory(server)}'); @@ -834,7 +982,9 @@ // If there are no versions in the cache, report a clearer error. if (versions.isEmpty) { throw PackageNotFoundException( - 'could not find package ${ref.name} in cache'); + 'could not find package ${ref.name} in cache', + hint: 'Try again without --offline!', + ); } return versions; @@ -850,18 +1000,19 @@ @override Future<Pubspec> describeUncached(PackageId id) { throw PackageNotFoundException( - '${id.name} ${id.version} is not available in your system cache'); + '${id.name} ${id.version} is not available in cache', + hint: 'Try again without --offline!', + ); } @override - Future<PackageStatus> status(PackageId id, {Duration maxAge}) async { + Future<PackageStatus> status(PackageId id, {Duration? maxAge}) async { // Do we have a cached version response on disk? final versionListing = await _cachedVersionListingResponse(id.toRef()); if (versionListing == null) { return PackageStatus(); } - final listing = versionListing[id]; // If we don't have the specific version we return the empty response. // // This should not happen. But in production we want to avoid a crash, since @@ -869,7 +1020,6 @@ // // TODO(sigurdm): Consider representing the non-existence of the // package-version in the return value. - assert(listing != null); return versionListing[id]?.status ?? PackageStatus(); } }
diff --git a/lib/src/source/path.dart b/lib/src/source/path.dart index b1dc26b..4679f98 100644 --- a/lib/src/source/path.dart +++ b/lib/src/source/path.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p; @@ -11,6 +9,7 @@ import '../exceptions.dart'; import '../io.dart'; +import '../language_version.dart'; import '../package_name.dart'; import '../pubspec.dart'; import '../source.dart'; @@ -64,7 +63,12 @@ /// original path but resolved relative to the containing path. The /// "relative" key will be `true` if the original path was relative. @override - PackageRef parseRef(String name, description, {String containingPath}) { + PackageRef parseRef( + String name, + description, { + String? containingPath, + LanguageVersion? languageVersion, + }) { if (description is! String) { throw FormatException('The description must be a path string.'); } @@ -90,7 +94,7 @@ @override PackageId parseId(String name, Version version, description, - {String containingPath}) { + {String? containingPath}) { if (description is! Map) { throw FormatException('The description must be a map.'); } @@ -126,9 +130,11 @@ /// /// For the descriptions where `relative` attribute is `true`, tries to make /// `path` relative to the specified [containingPath]. + /// + /// If [containingPath] is `null` they are serialized as absolute. @override - dynamic serializeDescription(String containingPath, description) { - if (description['relative']) { + dynamic serializeDescription(String? containingPath, description) { + if (description['relative'] == true && containingPath != null) { return { 'path': relativePathWithPosixSeparators( p.relative(description['path'], from: containingPath)), @@ -165,7 +171,8 @@ BoundPathSource(this.source, this.systemCache); @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async { + Future<List<PackageId>> doGetVersions( + PackageRef ref, Duration? maxAge) async { // There's only one package ID for a given path. We just need to find the // version. var pubspec = _loadPubspec(ref); @@ -183,10 +190,10 @@ } @override - String getDirectory(PackageId id, {String relativeFrom}) { + String getDirectory(PackageId id, {String? relativeFrom}) { return id.description['relative'] ? p.relative(id.description['path'], from: relativeFrom) - : id.description['path']; + : id.description['path']!; } /// Ensures that [description] is a valid path description and returns a
diff --git a/lib/src/source/sdk.dart b/lib/src/source/sdk.dart index aff6acc..1458d1b 100644 --- a/lib/src/source/sdk.dart +++ b/lib/src/source/sdk.dart
@@ -2,13 +2,12 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; import '../exceptions.dart'; +import '../language_version.dart'; import '../package_name.dart'; import '../pubspec.dart'; import '../sdk.dart'; @@ -35,7 +34,8 @@ /// Parses an SDK dependency. @override - PackageRef parseRef(String name, description, {String containingPath}) { + PackageRef parseRef(String name, description, + {String? containingPath, LanguageVersion? languageVersion}) { if (description is! String) { throw FormatException('The description must be an SDK name.'); } @@ -45,7 +45,7 @@ @override PackageId parseId(String name, Version version, description, - {String containingPath}) { + {String? containingPath}) { if (description is! String) { throw FormatException('The description must be an SDK name.'); } @@ -72,7 +72,8 @@ BoundSdkSource(this.source, this.systemCache); @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) async { + Future<List<PackageId>> doGetVersions( + PackageRef ref, Duration? maxAge) async { var pubspec = _loadPubspec(ref); var id = PackageId(ref.name, source, pubspec.version, ref.description); memoizePubspec(id, pubspec); @@ -95,13 +96,15 @@ /// Throws a [PackageNotFoundException] if [package]'s SDK is unavailable or /// doesn't contain the package. String _verifiedPackagePath(PackageName package) { - var identifier = package.description as String; - var sdk = sdks[identifier]; + var identifier = package.description as String?; + var sdk = sdks[identifier!]; if (sdk == null) { throw PackageNotFoundException('unknown SDK "$identifier"'); } else if (!sdk.isAvailable) { - throw PackageNotFoundException('the ${sdk.name} SDK is not available', - missingSdk: sdk); + throw PackageNotFoundException( + 'the ${sdk.name} SDK is not available', + hint: sdk.installMessage, + ); } var path = sdk.packagePath(package.name); @@ -112,7 +115,7 @@ } @override - String getDirectory(PackageId id, {String relativeFrom}) { + String getDirectory(PackageId id, {String? relativeFrom}) { try { return _verifiedPackagePath(id); } on PackageNotFoundException catch (error) {
diff --git a/lib/src/source/unknown.dart b/lib/src/source/unknown.dart index d98d0e2..baa46ea 100644 --- a/lib/src/source/unknown.dart +++ b/lib/src/source/unknown.dart
@@ -2,12 +2,11 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; +import '../language_version.dart'; import '../package_name.dart'; import '../pubspec.dart'; import '../source.dart'; @@ -44,12 +43,17 @@ int hashDescription(description) => description.hashCode; @override - PackageRef parseRef(String name, description, {String containingPath}) => + PackageRef parseRef( + String name, + description, { + String? containingPath, + LanguageVersion? languageVersion, + }) => PackageRef(name, this, description); @override PackageId parseId(String name, Version version, description, - {String containingPath}) => + {String? containingPath}) => PackageId(name, this, version, description); } @@ -63,7 +67,7 @@ _BoundUnknownSource(this.source, this.systemCache); @override - Future<List<PackageId>> doGetVersions(PackageRef ref, Duration maxAge) => + Future<List<PackageId>> doGetVersions(PackageRef ref, Duration? maxAge) => throw UnsupportedError( "Cannot get package versions from unknown source '${source.name}'."); @@ -73,7 +77,7 @@ /// Returns the directory where this package can be found locally. @override - String getDirectory(PackageId id, {String relativeFrom}) => + String getDirectory(PackageId id, {String? relativeFrom}) => throw UnsupportedError( "Cannot find a package from an unknown source '${source.name}'."); }
diff --git a/lib/src/source_registry.dart b/lib/src/source_registry.dart index 9c946eb..7e8aa84 100644 --- a/lib/src/source_registry.dart +++ b/lib/src/source_registry.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'source.dart'; import 'source/git.dart'; import 'source/hosted.dart'; @@ -27,7 +25,7 @@ /// /// This defaults to [hosted]. Source get defaultSource => _default; - Source _default; + late Source _default; /// The registered sources, in name order. List<Source> get all { @@ -60,7 +58,7 @@ throw StateError('Default source $name is not in the registry'); } - _default = _sources[name]; + _default = _sources[name]!; } /// Registers a new source. @@ -80,7 +78,7 @@ /// /// Returns an [UnknownSource] if no source with that name has been /// registered. If [name] is null, returns the default source. - Source operator [](String name) { + Source? operator [](String? name) { if (name == null) return _default; if (_sources.containsKey(name)) return _sources[name]; return UnknownSource(name);
diff --git a/lib/src/system_cache.dart b/lib/src/system_cache.dart index 298e775..d6b5876 100644 --- a/lib/src/system_cache.dart +++ b/lib/src/system_cache.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -23,7 +21,6 @@ import 'source/sdk.dart'; import 'source/unknown.dart'; import 'source_registry.dart'; -import 'utils.dart'; /// The system-wide cache of downloaded packages. /// @@ -38,19 +35,20 @@ static String defaultDir = (() { if (Platform.environment.containsKey('PUB_CACHE')) { - return Platform.environment['PUB_CACHE']; + return Platform.environment['PUB_CACHE']!; } else if (Platform.isWindows) { // %LOCALAPPDATA% is preferred as the cache location over %APPDATA%, because the latter is synchronised between // devices when the user roams between them, whereas the former is not. // The default cache dir used to be in %APPDATA%, so to avoid breaking old installs, // we use the old dir in %APPDATA% if it exists. Else, we use the new default location // in %LOCALAPPDATA%. - var appData = Platform.environment['APPDATA']; + // TODO(sigurdm): handle missing APPDATA. + var appData = Platform.environment['APPDATA']!; var appDataCacheDir = p.join(appData, 'Pub', 'Cache'); if (dirExists(appDataCacheDir)) { return appDataCacheDir; } - var localAppData = Platform.environment['LOCALAPPDATA']; + var localAppData = Platform.environment['LOCALAPPDATA']!; return p.join(localAppData, 'Pub', 'Cache'); } else { return '${Platform.environment['HOME']}/.pub-cache'; @@ -64,7 +62,7 @@ final sources = SourceRegistry(); /// The sources bound to this cache. - final _boundSources = <Source, BoundSource>{}; + final _boundSources = <Source?, BoundSource>{}; /// The built-in Git source bound to this cache. BoundGitSource get git => _boundSources[sources.git] as BoundGitSource; @@ -89,7 +87,7 @@ /// /// If [isOffline] is `true`, then the offline hosted source will be used. /// Defaults to `false`. - SystemCache({String rootDir, bool isOffline = false}) + SystemCache({String? rootDir, bool isOffline = false}) : rootDir = rootDir ?? SystemCache.defaultDir, tokenStore = TokenStore(dartConfigDir) { for (var source in sources.all) { @@ -102,8 +100,8 @@ } /// Returns the version of [source] bound to this cache. - BoundSource source(Source source) => - _boundSources.putIfAbsent(source, () => source.bind(this)); + BoundSource source(Source? source) => + _boundSources.putIfAbsent(source, () => source!.bind(this)); /// Loads the package identified by [id]. /// @@ -158,8 +156,8 @@ /// later stable version we return a prerelease version if it exists. /// /// Returns `null`, if unable to find the package. - Future<PackageId> getLatest( - PackageName package, { + Future<PackageId?> getLatest( + PackageName? package, { bool allowPrereleases = false, }) async { if (package == null) { @@ -172,21 +170,14 @@ return null; } - final latest = maxAll( - available.map((id) => id.version), - allowPrereleases ? Comparable.compare : Version.prioritize, - ); - + available.sort(allowPrereleases + ? (x, y) => x.version.compareTo(y.version) + : (x, y) => Version.prioritize(x.version, y.version)); if (package is PackageId && package.version.isPreRelease && - package.version > latest && - !allowPrereleases) { - return getLatest(package, allowPrereleases: true); + package.version > available.last.version) { + available.sort((x, y) => x.version.compareTo(y.version)); } - - // There should be exactly one entry in [available] matching [latest] - assert(available.where((id) => id.version == latest).length == 1); - - return available.firstWhere((id) => id.version == latest); + return available.last; } }
diff --git a/lib/src/utils.dart b/lib/src/utils.dart index fc3984e..2a5768e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart
@@ -9,7 +9,6 @@ import 'dart:math' as math; import 'package:crypto/crypto.dart' as crypto; -import 'package:meta/meta.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:stack_trace/stack_trace.dart'; @@ -376,7 +375,7 @@ // If we're using verbose logging, be more verbose but more accurate when // reporting timing information. - var msString = log.verbosity.isLevelVisible(log.Level.FINE) + var msString = log.verbosity.isLevelVisible(log.Level.fine) ? _padLeft(ms.toString(), 3, '0') : (ms ~/ 100).toString(); @@ -501,8 +500,7 @@ } /// Throw a [ApplicationException] with [message]. -@alwaysThrows -void fail(String message, [Object? innerError, StackTrace? innerTrace]) { +Never fail(String message, [Object? innerError, StackTrace? innerTrace]) { if (innerError != null) { throw WrappedException(message, innerError, innerTrace); } else { @@ -514,7 +512,7 @@ /// failed because of invalid input data. /// /// This will report the error and cause pub to exit with [exit_codes.DATA]. -void dataError(String message) => throw DataException(message); +Never dataError(String message) => throw DataException(message); /// Returns a UUID in v4 format as a `String`. ///
diff --git a/lib/src/validator.dart b/lib/src/validator.dart index c6a7b4a..1b07560 100644 --- a/lib/src/validator.dart +++ b/lib/src/validator.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:meta/meta.dart'; @@ -103,7 +101,7 @@ 'Make sure your SDK constraint excludes old versions:\n' '\n' 'environment:\n' - ' sdk: \"$newSdkConstraint\"'); + ' sdk: "$newSdkConstraint"'); } /// Returns whether [version1] and [version2] are pre-releases of the same version. @@ -123,8 +121,10 @@ /// package, in bytes. This is used to validate that it's not too big to /// upload to the server. static Future<void> runAll( - Entrypoint entrypoint, Future<int> packageSize, Uri serverUrl, - {List<String> hints, List<String> warnings, List<String> errors}) { + Entrypoint entrypoint, Future<int> packageSize, Uri? serverUrl, + {required List<String> hints, + required List<String> warnings, + required List<String> errors}) { var validators = [ GitignoreValidator(entrypoint), PubspecValidator(entrypoint), @@ -149,9 +149,7 @@ PubspecTypoValidator(entrypoint), LeakDetectionValidator(entrypoint), ]; - if (packageSize != null) { - validators.add(SizeValidator(entrypoint, packageSize)); - } + validators.add(SizeValidator(entrypoint, packageSize)); return Future.wait(validators.map((validator) => validator.validate())) .then((_) {
diff --git a/lib/src/validator/changelog.dart b/lib/src/validator/changelog.dart index 2f93903..614eba2 100644 --- a/lib/src/validator/changelog.dart +++ b/lib/src/validator/changelog.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -23,7 +21,7 @@ final changelog = entrypoint.root.changelogPath; if (changelog == null) { - warnings.add('Please add a`CHANGELOG.md` to your package. ' + warnings.add('Please add a `CHANGELOG.md` to your package. ' 'See https://dart.dev/tools/pub/publishing#important-files.'); return; } @@ -43,9 +41,6 @@ warnings.add('$changelog contains invalid UTF-8.\n' 'This will cause it to be displayed incorrectly on ' 'the Pub site (https://pub.dev).'); - } - - if (contents == null) { // Failed to decode contents, so there's nothing else to check. return; }
diff --git a/lib/src/validator/compiled_dartdoc.dart b/lib/src/validator/compiled_dartdoc.dart index 670862c..3f3376a 100644 --- a/lib/src/validator/compiled_dartdoc.dart +++ b/lib/src/validator/compiled_dartdoc.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as path;
diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart index c9f221a..5d158d1 100644 --- a/lib/src/validator/dependency.dart +++ b/lib/src/validator/dependency.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; @@ -223,8 +221,9 @@ constraint = '^${(dep.constraint as VersionRange).min}'; } else { constraint = '"${dep.constraint} ' - '<${(dep.constraint as VersionRange).min.nextBreaking}"'; + '<${(dep.constraint as VersionRange).min!.nextBreaking}"'; } + // TODO: Handle the case where `dep.constraint.min` is null. warnings .add('Your dependency on "${dep.name}" should have an upper bound. For ' @@ -240,7 +239,7 @@ void _warnAboutPrerelease(String dependencyName, VersionRange constraint) { final packageVersion = entrypoint.root.version; if (constraint.min != null && - constraint.min.isPreRelease && + constraint.min!.isPreRelease && !packageVersion.isPreRelease) { warnings.add('Packages dependent on a pre-release of another package ' 'should themselves be published as a pre-release version. '
diff --git a/lib/src/validator/dependency_override.dart b/lib/src/validator/dependency_override.dart index 8942be8..24e4e84 100644 --- a/lib/src/validator/dependency_override.dart +++ b/lib/src/validator/dependency_override.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:collection/collection.dart';
diff --git a/lib/src/validator/deprecated_fields.dart b/lib/src/validator/deprecated_fields.dart index 150d599..e1aee4f 100644 --- a/lib/src/validator/deprecated_fields.dart +++ b/lib/src/validator/deprecated_fields.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../entrypoint.dart';
diff --git a/lib/src/validator/directory.dart b/lib/src/validator/directory.dart index 9828f64..409e243 100644 --- a/lib/src/validator/directory.dart +++ b/lib/src/validator/directory.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as path;
diff --git a/lib/src/validator/executable.dart b/lib/src/validator/executable.dart index e9881d2..2163e8c 100644 --- a/lib/src/validator/executable.dart +++ b/lib/src/validator/executable.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p;
diff --git a/lib/src/validator/flutter_constraint.dart b/lib/src/validator/flutter_constraint.dart index 74c2a2e..d689a22 100644 --- a/lib/src/validator/flutter_constraint.dart +++ b/lib/src/validator/flutter_constraint.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart';
diff --git a/lib/src/validator/flutter_plugin_format.dart b/lib/src/validator/flutter_plugin_format.dart index 87fd3df..6f00f06 100644 --- a/lib/src/validator/flutter_plugin_format.dart +++ b/lib/src/validator/flutter_plugin_format.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart';
diff --git a/lib/src/validator/gitignore.dart b/lib/src/validator/gitignore.dart index df01214..4fb49b1 100644 --- a/lib/src/validator/gitignore.dart +++ b/lib/src/validator/gitignore.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; @@ -31,18 +29,27 @@ '--exclude-standard', '--recurse-submodules' ], workingDir: entrypoint.root.dir); + final root = git.repoRoot(entrypoint.root.dir) ?? entrypoint.root.dir; + var beneath = p.posix.joinAll( + p.split(p.normalize(p.relative(entrypoint.root.dir, from: root)))); + if (beneath == './') { + beneath = ''; + } String resolve(String path) { if (Platform.isWindows) { - return p.joinAll([entrypoint.root.dir, ...p.posix.split(path)]); + return p.joinAll([root, ...p.posix.split(path)]); } - return p.join(entrypoint.root.dir, path); + return p.join(root, path); } final unignoredByGitignore = Ignore.listFiles( + beneath: beneath, listDir: (dir) { var contents = Directory(resolve(dir)).listSync(); - return contents.map((entity) => p.posix.joinAll( - p.split(p.relative(entity.path, from: entrypoint.root.dir)))); + return contents + .where((e) => !(linkExists(e.path) && dirExists(e.path))) + .map((entity) => p.posix + .joinAll(p.split(p.relative(entity.path, from: root)))); }, ignoreForDir: (dir) { final gitIgnore = resolve('$dir/.gitignore'); @@ -52,15 +59,19 @@ return rules.isEmpty ? null : Ignore(rules); }, isDir: (dir) => dirExists(resolve(dir)), - ).toSet(); - + ).map((file) { + final relative = p.relative(resolve(file), from: entrypoint.root.dir); + return Platform.isWindows + ? p.posix.joinAll(p.split(relative)) + : relative; + }).toSet(); final ignoredFilesCheckedIn = checkedIntoGit .where((file) => !unignoredByGitignore.contains(file)) .toList(); if (ignoredFilesCheckedIn.isNotEmpty) { warnings.add(''' -${ignoredFilesCheckedIn.length} checked in ${pluralize('file', ignoredFilesCheckedIn.length)} ${ignoredFilesCheckedIn.length == 1 ? 'is' : 'are'} ignored by a `.gitignore`. +${ignoredFilesCheckedIn.length} checked-in ${pluralize('file', ignoredFilesCheckedIn.length)} ${ignoredFilesCheckedIn.length == 1 ? 'is' : 'are'} ignored by a `.gitignore`. Previous versions of Pub would include those in the published package. Consider adjusting your `.gitignore` files to not ignore those files, and if you do not wish to
diff --git a/lib/src/validator/language_version.dart b/lib/src/validator/language_version.dart index 6d71b22..e52a92a 100644 --- a/lib/src/validator/language_version.dart +++ b/lib/src/validator/language_version.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:analyzer/dart/ast/ast.dart';
diff --git a/lib/src/validator/leak_detection.dart b/lib/src/validator/leak_detection.dart index 53bf31d..7a398d4 100644 --- a/lib/src/validator/leak_detection.dart +++ b/lib/src/validator/leak_detection.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -75,7 +73,7 @@ errors.addAll(leaks.take(2).map((leak) => leak.toString())); final files = leaks - .map((leak) => leak.span.sourceUrl.toFilePath(windows: false)) + .map((leak) => leak.span.sourceUrl!.toFilePath(windows: false)) .toSet() .toList(growable: false) ..sort(); @@ -155,8 +153,8 @@ final List<String> testsWithNoLeaks; LeakPattern._({ - @required this.kind, - @required String pattern, + required this.kind, + required String pattern, Iterable<Pattern> allowed = const <Pattern>[], Map<int, double> entropyThresholds = const <int, double>{}, Iterable<String> testsWithLeaks = const <String>[], @@ -177,17 +175,17 @@ Iterable<LeakMatch> findPossibleLeaks(String file, String content) sync* { final source = SourceFile.fromString(content, url: file); for (final m in _pattern.allMatches(content)) { - if (_allowed.any((s) => m.group(0).contains(s))) { + if (_allowed.any((s) => m.group(0)!.contains(s))) { continue; } if (_entropyThresholds.entries - .any((entry) => _entropy(m.group(entry.key)) < entry.value)) { + .any((entry) => _entropy(m.group(entry.key)!) < entry.value)) { continue; } yield LeakMatch( this, - source.span(m.start, m.start + m.group(0).length), + source.span(m.start, m.start + m.group(0)!.length), ); } } @@ -554,7 +552,7 @@ '$_pemRequireLineBreak$_pemWSP', '=(?:(?:[a-zA-Z0-9+/]$_pemWSP){4})', _pemEnd('PGP PRIVATE KEY BLOCK'), - ].join(''), + ].join(), testsWithLeaks: [ ''' -----BEGIN PGP PRIVATE KEY BLOCK----- @@ -607,7 +605,7 @@ _pemRequireLineBreak, // Allow arbitrary whitespace and escaped line breaks _pemWSP, - ].join(''); + ].join(); String _pemBase64Block() => [ // Require base64 character in blocks of 4, allow arbirary whitespace @@ -629,10 +627,10 @@ // character, allow arbirary whitespace and escaped line breaks // in between. '(?:[a-zA-Z0-9+/]$_pemWSP){2}(?:=$_pemWSP){2}', - ].join(''), + ].join(), // End blocks '))?', - ].join(''); + ].join(); String _pemEnd(String label) => [ // Require \n, \r, \\r, or \\n, backslash escaping is allowed if the key @@ -641,10 +639,10 @@ // Allow arbitrary whitespace and escaped line breaks _pemWSP, '-----END $label-----', - ].join(''); + ].join(); String _pemKeyFormat(String label) => [ _pemBegin(label), _pemBase64Block(), _pemEnd(label), - ].join(''); + ].join();
diff --git a/lib/src/validator/license.dart b/lib/src/validator/license.dart index edca16d..1a2c68a 100644 --- a/lib/src/validator/license.dart +++ b/lib/src/validator/license.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as path;
diff --git a/lib/src/validator/name.dart b/lib/src/validator/name.dart index d484ed8..07d945c 100644 --- a/lib/src/validator/name.dart +++ b/lib/src/validator/name.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as path; @@ -74,7 +72,7 @@ builder ..write(source.substring(lastMatchEnd, match.start + 1)) ..write('_') - ..write(match.group(1).toLowerCase()); + ..write(match.group(1)!.toLowerCase()); lastMatchEnd = match.end; } builder.write(source.substring(lastMatchEnd));
diff --git a/lib/src/validator/null_safety_mixed_mode.dart b/lib/src/validator/null_safety_mixed_mode.dart index 401043e..42f9f77 100644 --- a/lib/src/validator/null_safety_mixed_mode.dart +++ b/lib/src/validator/null_safety_mixed_mode.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p;
diff --git a/lib/src/validator/pubspec.dart b/lib/src/validator/pubspec.dart index 20a7174..2a5e052 100644 --- a/lib/src/validator/pubspec.dart +++ b/lib/src/validator/pubspec.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as p;
diff --git a/lib/src/validator/pubspec_field.dart b/lib/src/validator/pubspec_field.dart index 482d696..8a5c23e 100644 --- a/lib/src/validator/pubspec_field.dart +++ b/lib/src/validator/pubspec_field.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import '../entrypoint.dart';
diff --git a/lib/src/validator/pubspec_typo.dart b/lib/src/validator/pubspec_typo.dart index 2e10ed6..9b04292 100644 --- a/lib/src/validator/pubspec_typo.dart +++ b/lib/src/validator/pubspec_typo.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import '../entrypoint.dart'; import '../levenshtein.dart'; import '../validator.dart'; @@ -16,8 +14,6 @@ Future validate() async { final fields = entrypoint.root.pubspec.fields; - if (fields == null) return; - /// Limit the number of typo warnings so as not to drown out the other /// warnings var warningCount = 0; @@ -73,4 +69,6 @@ 'publish_to', 'false_secrets', 'flutter', + 'screenshots', + 'platforms', ];
diff --git a/lib/src/validator/readme.dart b/lib/src/validator/readme.dart index 14d6b5e..85de479 100644 --- a/lib/src/validator/readme.dart +++ b/lib/src/validator/readme.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert';
diff --git a/lib/src/validator/relative_version_numbering.dart b/lib/src/validator/relative_version_numbering.dart index 6609074..eb4246c 100644 --- a/lib/src/validator/relative_version_numbering.dart +++ b/lib/src/validator/relative_version_numbering.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. -// @dart=2.10 - import 'dart:async'; +import 'package:collection/collection.dart' show IterableExtension; + import '../entrypoint.dart'; import '../exceptions.dart'; import '../null_safety_analysis.dart'; @@ -18,7 +18,7 @@ static const String semverUrl = 'https://dart.dev/tools/pub/versioning#semantic-versions'; - final Uri _server; + final Uri? _server; RelativeVersionNumberingValidator(Entrypoint entrypoint, this._server) : super(entrypoint); @@ -35,9 +35,8 @@ existingVersions = []; } existingVersions.sort((a, b) => a.version.compareTo(b.version)); - final previousVersion = existingVersions.lastWhere( - (id) => id.version < entrypoint.root.version, - orElse: () => null); + final previousVersion = existingVersions + .lastWhereOrNull((id) => id.version < entrypoint.root.version); if (previousVersion == null) return; final previousPubspec =
diff --git a/lib/src/validator/sdk_constraint.dart b/lib/src/validator/sdk_constraint.dart index 68de6bf..ff25e53 100644 --- a/lib/src/validator/sdk_constraint.dart +++ b/lib/src/validator/sdk_constraint.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:pub_semver/pub_semver.dart'; @@ -52,7 +50,7 @@ 'Expand it manually instead:\n' '\n' 'environment:\n' - ' sdk: \"$dartConstraintWithoutCaret\"'); + ' sdk: "$dartConstraintWithoutCaret"'); } if (dartConstraint.max == null) {
diff --git a/lib/src/validator/size.dart b/lib/src/validator/size.dart index f873dfe..e989518 100644 --- a/lib/src/validator/size.dart +++ b/lib/src/validator/size.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:math' as math; @@ -12,7 +10,7 @@ import '../validator.dart'; /// The maximum size of the package to upload (100 MB). -const _MAX_SIZE = 100 * 1024 * 1024; +const _maxSize = 100 * 1024 * 1024; /// A validator that validates that a package isn't too big. class SizeValidator extends Validator { @@ -23,7 +21,7 @@ @override Future validate() { return packageSize.then((size) { - if (size <= _MAX_SIZE) return; + if (size <= _maxSize) return; var sizeInMb = (size / math.pow(2, 20)).toStringAsPrecision(4); // Current implementation of Package.listFiles skips hidden files var ignoreExists = fileExists(entrypoint.root.path('.gitignore'));
diff --git a/lib/src/validator/strict_dependencies.dart b/lib/src/validator/strict_dependencies.dart index 33e1210..881c55c 100644 --- a/lib/src/validator/strict_dependencies.dart +++ b/lib/src/validator/strict_dependencies.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:analyzer/dart/ast/ast.dart'; @@ -47,9 +45,9 @@ } for (var directive in directives) { - Uri url; + Uri? url; try { - url = Uri.parse(directive.uri.stringValue); + url = Uri.parse(directive.uri.stringValue!); } on FormatException catch (_) { // Ignore a format exception. [url] will be null, and we'll emit an // "Invalid URL" warning below.
diff --git a/pubspec.yaml b/pubspec.yaml index 23fc0c8..a7d9bb4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml
@@ -6,10 +6,10 @@ dependencies: # Note: Pub's test infrastructure assumes that any dependencies used in tests # will be hosted dependencies. - analyzer: ^1.5.0 + analyzer: ^2.7.0 args: ^2.1.0 async: ^2.6.1 - cli_util: ^0.3.0 + cli_util: ^0.3.5 collection: ^1.15.0 crypto: ^3.0.1 frontend_server_client: ^2.0.0 @@ -18,16 +18,17 @@ meta: ^1.3.0 oauth2: ^2.0.0 path: ^1.8.0 - pedantic: ^1.11.0 pool: ^1.5.0 - pub_semver: ^2.0.0 + pub_semver: ^2.1.0 shelf: ^1.1.1 source_span: ^1.8.1 stack_trace: ^1.10.0 + usage: ^4.0.2 yaml: ^3.1.0 yaml_edit: ^2.0.0 dev_dependencies: + lints: ^1.0.1 shelf_test_handler: ^2.0.0 test: ^1.17.3 test_descriptor: ^2.0.0
diff --git a/test/add/common/add_test.dart b/test/add/common/add_test.dart index 51d5b71..82e098b 100644 --- a/test/add/common/add_test.dart +++ b/test/add/common/add_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io' show File; import 'package:path/path.dart' as p; @@ -15,7 +13,7 @@ void main() { test('URL encodes the package name', () async { - await serveNoPackages(); + await servePackages(); await d.appDir({}).create(); @@ -39,49 +37,48 @@ }); group('normally', () { - test('fails if extra arguments are passed', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); - - await d.dir(appPath, [ - d.pubspec({'name': 'myapp'}) - ]).create(); - - await pubAdd( - args: ['foo', '^1.2.2'], - exitCode: exit_codes.USAGE, - error: contains('Takes only a single argument.')); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - }), - d.nothing('.dart_tool/package_config.json'), - d.nothing('pubspec.lock'), - d.nothing('.packages'), - ]).validate(); - }); - test('adds a package from a pub server', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); await pubAdd(args: ['foo:1.2.3']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': '1.2.3'}).validate(); }); + test('adds multiple package from a pub server', () async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.serve('bar', '1.1.0'); + server.serve('baz', '2.5.3'); + + await d.appDir({}).create(); + + await pubAdd(args: ['foo:1.2.3', 'bar:1.1.0', 'baz:2.5.3']); + + await d.cacheDir( + {'foo': '1.2.3', 'bar': '1.1.0', 'baz': '2.5.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + d.packageConfigEntry(name: 'baz', version: '2.5.3'), + ]).validate(); + await d + .appDir({'foo': '1.2.3', 'bar': '1.1.0', 'baz': '2.5.3'}).validate(); + }); + test( 'does not remove empty dev_dependencies while adding to normal dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.file('pubspec.yaml', ''' @@ -98,7 +95,9 @@ await pubAdd(args: ['foo:1.2.3']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -111,7 +110,8 @@ test('dry run does not actually add the package or modify the pubspec', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); @@ -133,7 +133,8 @@ test( 'adds a package from a pub server even when dependencies key does not exist', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir(appPath, [ d.pubspec({'name': 'myapp'}) @@ -142,16 +143,17 @@ await pubAdd(args: ['foo:1.2.3']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': '1.2.3'}).validate(); }); group('warns user to use pub upgrade if package exists', () { test('if package is added without a version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.appDir({'foo': '1.2.2'}).create(); @@ -166,10 +168,9 @@ }); test('if package is added with a specific version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.appDir({'foo': '1.2.2'}).create(); @@ -184,10 +185,9 @@ }); test('if package is added with a version constraint range', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.appDir({'foo': '1.2.2'}).create(); @@ -203,10 +203,9 @@ }); test('removes dev_dependency and add to normal dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.file('pubspec.yaml', ''' @@ -227,7 +226,9 @@ 'adding it to dependencies instead.')); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -239,10 +240,9 @@ group('dependency override', () { test('passes if package does not specify a range', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -255,7 +255,9 @@ await pubAdd(args: ['foo']); await d.cacheDir({'foo': '1.2.2'}).validate(); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', @@ -266,9 +268,8 @@ }); test('passes if constraint matches git dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.2.3')]).create(); @@ -297,9 +298,8 @@ }); test('passes if constraint matches path dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d.dir( 'foo', [d.libDir('foo'), d.libPubspec('foo', '1.2.2')]).create(); @@ -327,9 +327,8 @@ }); test('fails with bad version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir(appPath, [ d.pubspec({'name': 'myapp', 'dependencies': {}}) @@ -350,10 +349,9 @@ }); test('fails if constraint does not match override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -383,9 +381,8 @@ }); test('fails if constraint matches git dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -423,9 +420,8 @@ test('fails if constraint does not match path dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d.dir( 'foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -464,7 +460,8 @@ group('--dev', () { test('--dev adds packages to dev_dependencies instead', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir(appPath, [ d.pubspec({'name': 'myapp', 'dev_dependencies': {}}) @@ -472,7 +469,9 @@ await pubAdd(args: ['--dev', 'foo:1.2.3']); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -484,10 +483,9 @@ group('warns user to use pub upgrade if package exists', () { test('if package is added without a version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -512,10 +510,9 @@ }); test('if package is added with a specific version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -540,10 +537,9 @@ }); test('if package is added with a version constraint range', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -570,10 +566,9 @@ group('dependency override', () { test('passes if package does not specify a range', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -586,7 +581,9 @@ await pubAdd(args: ['foo', '--dev']); await d.cacheDir({'foo': '1.2.2'}).validate(); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', @@ -597,10 +594,8 @@ }); test('passes if constraint is git dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); - + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.2.3')]).create(); @@ -628,9 +623,8 @@ }); test('passes if constraint matches path dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d.dir( 'foo', [d.libDir('foo'), d.libPubspec('foo', '1.2.2')]).create(); @@ -658,10 +652,9 @@ }); test('fails if constraint does not match override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -691,9 +684,8 @@ }); test('fails if constraint matches git dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -731,9 +723,9 @@ test('fails if constraint does not match path dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); + await d.dir( 'foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -772,10 +764,9 @@ test( 'prints information saying that package is already a dependency if it ' 'already exists and exits with a usage exception', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2'); await d.dir(appPath, [ d.pubspec({ @@ -807,9 +798,8 @@ /// Differs from the previous test because this tests YAML in flow format. test('adds to empty ', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - }); + final server = await servePackages(); + server.serve('bar', '1.0.0'); await d.dir(appPath, [ d.file('pubspec.yaml', ''' @@ -827,10 +817,9 @@ }); test('preserves comments', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - builder.serve('foo', '1.0.0'); - }); + await servePackages() + ..serve('bar', '1.0.0') + ..serve('foo', '1.0.0'); await d.dir(appPath, [ d.file('pubspec.yaml', '''
diff --git a/test/add/common/invalid_options.dart b/test/add/common/invalid_options.dart index 17262d2..f5bf23d 100644 --- a/test/add/common/invalid_options.dart +++ b/test/add/common/invalid_options.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -41,12 +39,10 @@ test('cannot use both --path and --host-<option> flags', () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveNoPackages(); - globalPackageServer.serveErrors(); + (await servePackages()).serveErrors(); - final server = await PackageServer.start((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await startPackageServer(); + server.serve('foo', '1.2.3'); await d .dir('bar', [d.libDir('bar'), d.libPubspec('foo', '0.0.1')]).create(); @@ -78,12 +74,10 @@ test('cannot use both --hosted-url and --git-<option> flags', () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveNoPackages(); - globalPackageServer.serveErrors(); + (await servePackages()).serveErrors(); - final server = await PackageServer.start((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await startPackageServer(); + server.serve('foo', '1.2.3'); ensureGit();
diff --git a/test/add/common/version_constraint_test.dart b/test/add/common/version_constraint_test.dart index 22df8bc..f058082 100644 --- a/test/add/common/version_constraint_test.dart +++ b/test/add/common/version_constraint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,86 +10,96 @@ void main() { test('allows empty version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '0.2.3'); - builder.serve('foo', '1.0.1'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '2.0.0-dev'); - builder.serve('foo', '1.3.4-dev'); - }); + await servePackages() + ..serve('foo', '0.2.3') + ..serve('foo', '1.0.1') + ..serve('foo', '1.2.3') + ..serve('foo', '2.0.0-dev') + ..serve('foo', '1.3.4-dev'); await d.appDir({}).create(); await pubAdd(args: ['foo']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': '^1.2.3'}).validate(); }); test('allows specific version constraint', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); await pubAdd(args: ['foo:1.2.3']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': '1.2.3'}).validate(); }); test('allows specific pre-release version constraint', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3-dev')); + final server = await servePackages(); + server.serve('foo', '1.2.3-dev'); await d.appDir({}).create(); await pubAdd(args: ['foo:1.2.3-dev']); await d.cacheDir({'foo': '1.2.3-dev'}).validate(); - await d.appPackagesFile({'foo': '1.2.3-dev'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3-dev'), + ]).validate(); await d.appDir({'foo': '1.2.3-dev'}).validate(); }); test('allows the "any" version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '0.2.3'); - builder.serve('foo', '1.0.1'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '2.0.0-dev'); - builder.serve('foo', '1.3.4-dev'); - }); + await servePackages() + ..serve('foo', '0.2.3') + ..serve('foo', '1.0.1') + ..serve('foo', '1.2.3') + ..serve('foo', '2.0.0-dev') + ..serve('foo', '1.3.4-dev'); await d.appDir({}).create(); await pubAdd(args: ['foo:any']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': 'any'}).validate(); }); test('allows version constraint range', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); await pubAdd(args: ['foo:>1.2.0 <2.0.0']); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({'foo': '>1.2.0 <2.0.0'}).validate(); }); test( 'empty constraint allows it to choose the latest version not in conflict', () async { - await servePackages((builder) { - builder.serve('foo', '0.1.0'); - builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'}); - builder.serve('bar', '2.0.3'); - builder.serve('bar', '2.0.4'); - }); + await servePackages() + ..serve('foo', '0.1.0') + ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'}) + ..serve('bar', '2.0.3') + ..serve('bar', '2.0.4'); await d.appDir({'bar': '2.0.3'}).create(); @@ -100,12 +108,16 @@ await d.appDir({'foo': '^0.1.0', 'bar': '2.0.3'}).validate(); await d.cacheDir({'foo': '0.1.0', 'bar': '2.0.3'}).validate(); - await d.appPackagesFile({'foo': '0.1.0', 'bar': '2.0.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '0.1.0'), + d.packageConfigEntry(name: 'bar', version: '2.0.3'), + ]).validate(); }); group('does not update pubspec if no available version found', () { test('simple', () async { - await servePackages((builder) => builder.serve('foo', '1.0.3')); + final server = await servePackages(); + server.serve('foo', '1.0.3'); await d.appDir({}).create(); @@ -126,11 +138,10 @@ }); test('transitive', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'}); - builder.serve('bar', '2.0.3'); - builder.serve('bar', '2.0.4'); - }); + await servePackages() + ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'}) + ..serve('bar', '2.0.3') + ..serve('bar', '2.0.4'); await d.appDir({'bar': '2.0.3'}).create();
diff --git a/test/add/common/version_resolution_test.dart b/test/add/common/version_resolution_test.dart index a6ad690..0f44d2b 100644 --- a/test/add/common/version_resolution_test.dart +++ b/test/add/common/version_resolution_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -15,10 +13,10 @@ test('unlocks transitive dependencies', () async { /// The server used to only have the foo v3.2.1 as the latest, /// so pub get will create a pubspec.lock to foo 3.2.1 - await servePackages((builder) { - builder.serve('foo', '3.2.1'); - builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); - }); + final server = await servePackages(); + + server.serve('foo', '3.2.1'); + server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); await d.appDir({'bar': '1.0.0'}).create(); await pubGet(); @@ -26,66 +24,69 @@ /// foo's package creator releases a newer version of foo, and we /// want to test that this is what the user gets when they run /// pub add foo. - globalPackageServer.add((builder) { - builder.serve('foo', '3.5.0'); - builder.serve('foo', '3.1.0'); - builder.serve('foo', '2.5.0'); - }); + server.serve('foo', '3.5.0'); + server.serve('foo', '3.1.0'); + server.serve('foo', '2.5.0'); await pubAdd(args: ['foo']); await d.appDir({'foo': '^3.5.0', 'bar': '1.0.0'}).validate(); await d.cacheDir({'foo': '3.5.0', 'bar': '1.0.0'}).validate(); - await d.appPackagesFile({'foo': '3.5.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '3.5.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('chooses the appropriate version to not break other dependencies', () async { /// The server used to only have the foo v3.2.1 as the latest, /// so pub get will create a pubspec.lock to foo 3.2.1 - await servePackages((builder) { - builder.serve('foo', '3.2.1'); - builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); - }); + final server = await servePackages(); + + server.serve('foo', '3.2.1'); + server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); await d.appDir({'bar': '1.0.0'}).create(); await pubGet(); - globalPackageServer.add((builder) { - builder.serve('foo', '4.0.0'); - builder.serve('foo', '2.0.0'); - }); + server.serve('foo', '4.0.0'); + server.serve('foo', '2.0.0'); await pubAdd(args: ['foo']); await d.appDir({'foo': '^3.2.1', 'bar': '1.0.0'}).validate(); await d.cacheDir({'foo': '3.2.1', 'bar': '1.0.0'}).validate(); - await d.appPackagesFile({'foo': '3.2.1', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '3.2.1'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('may upgrade other packages if they allow a later version to be chosen', () async { /// The server used to only have the foo v3.2.1 as the latest, /// so pub get will create a pubspec.lock to foo 3.2.1 - await servePackages((builder) { - builder.serve('foo', '3.2.1'); - builder.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); - }); + final server = await servePackages(); + + server.serve('foo', '3.2.1'); + server.serve('bar', '1.0.0', deps: {'foo': '^3.2.1'}); await d.appDir({'bar': '^1.0.0'}).create(); await pubGet(); - globalPackageServer.add((builder) { - builder.serve('foo', '5.0.0'); - builder.serve('foo', '4.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('bar', '1.5.0', deps: {'foo': '^4.0.0'}); - }); + server.serve('foo', '5.0.0'); + server.serve('foo', '4.0.0'); + server.serve('foo', '2.0.0'); + server.serve('bar', '1.5.0', deps: {'foo': '^4.0.0'}); await pubAdd(args: ['foo']); await d.appDir({'foo': '^4.0.0', 'bar': '^1.0.0'}).validate(); await d.cacheDir({'foo': '4.0.0', 'bar': '1.5.0'}).validate(); - await d.appPackagesFile({'foo': '4.0.0', 'bar': '1.5.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '4.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.5.0'), + ]).validate(); }); }
diff --git a/test/add/git/git_test.dart b/test/add/git/git_test.dart index b120e38..d976172 100644 --- a/test/add/git/git_test.dart +++ b/test/add/git/git_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -158,9 +156,8 @@ }); test('can be overriden by dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d.git( 'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -176,7 +173,9 @@ await pubAdd(args: ['foo', '--git-url', '../foo.git']); await d.cacheDir({'foo': '1.2.2'}).validate(); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', @@ -187,4 +186,18 @@ }) ]).validate(); }); + + test('fails if multiple packages passed for git source', () async { + ensureGit(); + + await d.git( + 'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); + + await d.appDir({}).create(); + + await pubAdd( + args: ['foo', 'bar', 'baz', '--git-url', '../foo.git'], + exitCode: exit_codes.USAGE, + error: contains('Can only add a single git package at a time.')); + }); }
diff --git a/test/add/git/ref_test.dart b/test/add/git/ref_test.dart index fadd80a..11dfc0b 100644 --- a/test/add/git/ref_test.dart +++ b/test/add/git/ref_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/add/git/subdir_test.dart b/test/add/git/subdir_test.dart index 3bf381a..8e8c39c 100644 --- a/test/add/git/subdir_test.dart +++ b/test/add/git/subdir_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -32,10 +30,11 @@ ]) ]) ]).validate(); - - await d.appPackagesFile({ - 'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub', + path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')), + ]).validate(); await d.appDir({ 'sub': { @@ -70,9 +69,11 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub', + path: pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir')), + ]).validate(); await d.appDir({ 'sub': {
diff --git a/test/add/hosted/non_default_pub_server_test.dart b/test/add/hosted/non_default_pub_server_test.dart index 33b6753..60538e3 100644 --- a/test/add/hosted/non_default_pub_server_test.dart +++ b/test/add/hosted/non_default_pub_server_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -14,13 +12,12 @@ test('adds a package from a non-default pub server', () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveErrors(); + (await servePackages()).serveErrors(); - var server = await PackageServer.start((builder) { - builder.serve('foo', '0.2.5'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '0.2.5'); + server.serve('foo', '1.1.0'); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); @@ -29,7 +26,9 @@ await pubAdd(args: ['foo:1.2.3', '--hosted-url', url]); await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({ 'foo': { 'version': '1.2.3', @@ -38,6 +37,49 @@ }).validate(); }); + test('adds multiple packages from a non-default pub server', () async { + // Make the default server serve errors. Only the custom server should + // be accessed. + (await servePackages()).serveErrors(); + + final server = await servePackages(); + server.serve('foo', '1.1.0'); + server.serve('foo', '1.2.3'); + server.serve('bar', '0.2.5'); + server.serve('bar', '3.2.3'); + server.serve('baz', '0.1.3'); + server.serve('baz', '1.3.5'); + + await d.appDir({}).create(); + + final url = server.url; + + await pubAdd( + args: ['foo:1.2.3', 'bar:3.2.3', 'baz:1.3.5', '--hosted-url', url]); + + await d.cacheDir({'foo': '1.2.3', 'bar': '3.2.3', 'baz': '1.3.5'}, + port: server.port).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + d.packageConfigEntry(name: 'bar', version: '3.2.3'), + d.packageConfigEntry(name: 'baz', version: '1.3.5'), + ]).validate(); + await d.appDir({ + 'foo': { + 'version': '1.2.3', + 'hosted': {'name': 'foo', 'url': url} + }, + 'bar': { + 'version': '3.2.3', + 'hosted': {'name': 'bar', 'url': url} + }, + 'baz': { + 'version': '1.3.5', + 'hosted': {'name': 'baz', 'url': url} + } + }).validate(); + }); + test('fails when adding from an invalid url', () async { ensureGit(); @@ -66,13 +108,12 @@ () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveErrors(); + (await servePackages()).serveErrors(); - var server = await PackageServer.start((builder) { - builder.serve('foo', '0.2.5'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '0.2.5'); + server.serve('foo', '1.1.0'); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); @@ -81,7 +122,9 @@ await pubAdd(args: ['foo', '--hosted-url', url]); await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({ 'foo': { 'version': '^1.2.3', @@ -94,13 +137,12 @@ () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveErrors(); + (await servePackages()).serveErrors(); - var server = await PackageServer.start((builder) { - builder.serve('foo', '0.2.5'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '0.2.5'); + server.serve('foo', '1.1.0'); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); @@ -109,7 +151,9 @@ await pubAdd(args: ['foo', '--hosted-url', url]); await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({ 'foo': { 'version': '^1.2.3', @@ -123,13 +167,11 @@ 'constraint', () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveErrors(); - - var server = await PackageServer.start((builder) { - builder.serve('foo', '0.2.5'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.3'); - }); + (await servePackages()).serveErrors(); + final server = await servePackages(); + server.serve('foo', '0.2.5'); + server.serve('foo', '1.1.0'); + server.serve('foo', '1.2.3'); await d.appDir({}).create(); @@ -138,7 +180,9 @@ await pubAdd(args: ['foo:any', '--hosted-url', url]); await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); await d.appDir({ 'foo': { 'version': 'any',
diff --git a/test/add/path/absolute_path_test.dart b/test/add/path/absolute_path_test.dart index dc74638..5e63679 100644 --- a/test/add/path/absolute_path_test.dart +++ b/test/add/path/absolute_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -22,7 +20,9 @@ await pubAdd(args: ['foo', '--path', absolutePath]); - await d.appPackagesFile({'foo': absolutePath}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: absolutePath), + ]).validate(); await d.appDir({ 'foo': {'path': absolutePath} @@ -43,6 +43,28 @@ }).validate(); }); + test('fails when adding multiple packages through local path', () async { + ensureGit(); + + await d.git( + 'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); + + await d.appDir({}).create(); + final absolutePath = path.join(d.sandbox, 'foo'); + + await pubAdd( + args: ['foo:2.0.0', 'bar:0.1.3', 'baz:1.3.1', '--path', absolutePath], + error: contains('Can only add a single local package at a time.'), + exitCode: exit_codes.USAGE); + + await d.appDir({}).validate(); + await d.dir(appPath, [ + d.nothing('.dart_tool/package_config.json'), + d.nothing('pubspec.lock'), + d.nothing('.packages'), + ]).validate(); + }); + test('fails when adding with an invalid version constraint', () async { ensureGit(); @@ -90,9 +112,8 @@ }); test('can be overriden by dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create(); @@ -108,7 +129,9 @@ await pubAdd(args: ['foo', '--path', absolutePath]); await d.cacheDir({'foo': '1.2.2'}).validate(); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp',
diff --git a/test/add/path/relative_path_test.dart b/test/add/path/relative_path_test.dart index 9d443e8..e08ba3c 100644 --- a/test/add/path/relative_path_test.dart +++ b/test/add/path/relative_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io' show Platform; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -21,7 +19,9 @@ await pubAdd(args: ['foo', '--path', '../foo']); - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); await d.appDir({ 'foo': {'path': '../foo'} @@ -40,7 +40,9 @@ output: contains('Changed 1 dependency in myapp!'), ); - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); await d.appDir({ 'foo': {'path': '../foo'} @@ -104,9 +106,8 @@ }); test('can be overriden by dependency override', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.2'); await d .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create(); @@ -121,7 +122,9 @@ await pubAdd(args: ['foo', '--path', '../foo']); await d.cacheDir({'foo': '1.2.2'}).validate(); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp',
diff --git a/test/add/sdk/sdk_test.dart b/test/add/sdk/sdk_test.dart index 1ded16e..ff7d442 100644 --- a/test/add/sdk/sdk_test.dart +++ b/test/add/sdk/sdk_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -13,9 +11,8 @@ void main() { setUp(() async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - }); + final server = await servePackages(); + server.serve('bar', '1.0.0'); await d.dir('flutter', [ d.dir('packages', [ @@ -45,11 +42,12 @@ 'foo': {'sdk': 'flutter', 'version': '^0.0.1'} } }), - d.packagesFile({ - 'myapp': '.', - 'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'), - 'bar': '1.0.0' - }) + ]).validate(); + + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), ]).validate(); }); @@ -68,11 +66,11 @@ 'foo': {'sdk': 'flutter', 'version': '0.0.1'} } }), - d.packagesFile({ - 'myapp': '.', - 'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'), - 'bar': '1.0.0' - }) + ]).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), ]).validate(); }); @@ -82,11 +80,10 @@ args: ['baz', '--sdk', 'flutter'], environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')}); - await d.dir(appPath, [ - d.packagesFile({ - 'myapp': '.', - 'baz': p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz') - }) + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'baz', + path: p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz')) ]).validate(); });
diff --git a/test/cache/add/adds_latest_matching_version_test.dart b/test/cache/add/adds_latest_matching_version_test.dart index d7e26c4..7bf9625 100644 --- a/test/cache/add/adds_latest_matching_version_test.dart +++ b/test/cache/add/adds_latest_matching_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:test/test.dart'; @@ -15,12 +13,11 @@ test( 'adds the latest version of the package matching the ' 'version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '2.0.0-dev'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.2.2') + ..serve('foo', '1.2.3') + ..serve('foo', '2.0.0-dev') + ..serve('foo', '2.0.0'); await runPub( args: ['cache', 'add', 'foo', '-v', '>=1.0.0 <2.0.0'],
diff --git a/test/cache/add/adds_latest_version_test.dart b/test/cache/add/adds_latest_version_test.dart index 6a8b795..cf34857 100644 --- a/test/cache/add/adds_latest_version_test.dart +++ b/test/cache/add/adds_latest_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('adds the latest stable version of the package', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.4-dev'); - }); + await servePackages() + ..serve('foo', '1.2.2') + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.4-dev'); await runPub( args: ['cache', 'add', 'foo'], output: 'Downloading foo 1.2.3...');
diff --git a/test/cache/add/all_adds_all_matching_versions_test.dart b/test/cache/add/all_adds_all_matching_versions_test.dart index bfffa7f..a05e8dc 100644 --- a/test/cache/add/all_adds_all_matching_versions_test.dart +++ b/test/cache/add/all_adds_all_matching_versions_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,12 +9,11 @@ void main() { test('"--all" adds all matching versions of the package', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - builder.serve('foo', '1.2.3-dev'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.2.2') + ..serve('foo', '1.2.3-dev') + ..serve('foo', '1.2.3') + ..serve('foo', '2.0.0'); await runPub( args: ['cache', 'add', 'foo', '-v', '>=1.0.0 <2.0.0', '--all'],
diff --git a/test/cache/add/all_with_some_versions_present_test.dart b/test/cache/add/all_with_some_versions_present_test.dart index da4da98..7b5b36d 100644 --- a/test/cache/add/all_with_some_versions_present_test.dart +++ b/test/cache/add/all_with_some_versions_present_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,12 +9,11 @@ void main() { test('"--all" adds all non-installed versions of the package', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.1'); - builder.serve('foo', '1.2.2'); - builder.serve('foo', '1.2.3'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.2.1') + ..serve('foo', '1.2.2') + ..serve('foo', '1.2.3') + ..serve('foo', '2.0.0'); // Install a couple of versions first. await runPub(
diff --git a/test/cache/add/already_cached_test.dart b/test/cache/add/already_cached_test.dart index 9bf8df3..8c74da9 100644 --- a/test/cache/add/already_cached_test.dart +++ b/test/cache/add/already_cached_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,9 +9,8 @@ void main() { test('does nothing if the package is already cached', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); // Run once to put it in the cache. await runPub(
diff --git a/test/cache/add/bad_version_test.dart b/test/cache/add/bad_version_test.dart index e0a57e0..4e93331 100644 --- a/test/cache/add/bad_version_test.dart +++ b/test/cache/add/bad_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,16 +9,10 @@ void main() { test('fails if the version constraint cannot be parsed', () { - return runPub(args: ['cache', 'add', 'foo', '-v', '1.0'], error: ''' - Could not parse version "1.0". Unknown text at "1.0". - - Usage: pub cache add <package> [--version <constraint>] [--all] - -h, --help Print this usage information. - --all Install all matching versions. - -v, --version Version constraint. - - Run "pub help" to see global options. - See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. - ''', exitCode: exit_codes.USAGE); + return runPub( + args: ['cache', 'add', 'foo', '-v', '1.0'], + error: contains('Could not parse version "1.0". Unknown text at "1.0".'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/cache/add/missing_package_arg_test.dart b/test/cache/add/missing_package_arg_test.dart index 2274992..456342b 100644 --- a/test/cache/add/missing_package_arg_test.dart +++ b/test/cache/add/missing_package_arg_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,16 +9,10 @@ void main() { test('fails if no package was given', () { - return runPub(args: ['cache', 'add'], error: ''' - No package to add given. - - Usage: pub cache add <package> [--version <constraint>] [--all] - -h, --help Print this usage information. - --all Install all matching versions. - -v, --version Version constraint. - - Run "pub help" to see global options. - See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. - ''', exitCode: exit_codes.USAGE); + return runPub( + args: ['cache', 'add'], + error: contains('No package to add given.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/cache/add/no_matching_version_test.dart b/test/cache/add/no_matching_version_test.dart index d395f29..a860294 100644 --- a/test/cache/add/no_matching_version_test.dart +++ b/test/cache/add/no_matching_version_test.dart
@@ -2,18 +2,15 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart'; void main() { test('fails if no version matches the version constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.2'); - builder.serve('foo', '1.2.3'); - }); + await servePackages() + ..serve('foo', '1.2.2') + ..serve('foo', '1.2.3'); await runPub( args: ['cache', 'add', 'foo', '-v', '>2.0.0'],
diff --git a/test/cache/add/package_not_found_test.dart b/test/cache/add/package_not_found_test.dart index 4179319..caf45f4 100644 --- a/test/cache/add/package_not_found_test.dart +++ b/test/cache/add/package_not_found_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,12 +9,13 @@ void main() { test('fails if the package cound not be found on the source', () async { - await serveNoPackages(); + await servePackages(); await runPub( args: ['cache', 'add', 'foo'], - error: RegExp(r"Package doesn't exist \(could not find package foo at " - r'http://.*\)\.'), + error: RegExp( + r'Package not available \(could not find package foo at http://.*\)\.', + ), exitCode: exit_codes.UNAVAILABLE); }); }
diff --git a/test/cache/add/unexpected_arguments_test.dart b/test/cache/add/unexpected_arguments_test.dart index 66174db..1e4fa54 100644 --- a/test/cache/add/unexpected_arguments_test.dart +++ b/test/cache/add/unexpected_arguments_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,16 +9,10 @@ void main() { test('fails if there are extra arguments', () { - return runPub(args: ['cache', 'add', 'foo', 'bar', 'baz'], error: ''' - Unexpected arguments "bar" and "baz". - - Usage: pub cache add <package> [--version <constraint>] [--all] - -h, --help Print this usage information. - --all Install all matching versions. - -v, --version Version constraint. - - Run "pub help" to see global options. - See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. - ''', exitCode: exit_codes.USAGE); + return runPub( + args: ['cache', 'add', 'foo', 'bar', 'baz'], + error: contains('Unexpected arguments "bar" and "baz".'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/cache/clean_test.dart b/test/cache/clean_test.dart index 1ba2ac7..7a79bc8 100644 --- a/test/cache/clean_test.dart +++ b/test/cache/clean_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -19,9 +17,9 @@ }); test('running pub cache clean --force deletes cache', () async { - await servePackages((b) => b + await servePackages() ..serve('foo', '1.1.2') - ..serve('bar', '1.2.3')); + ..serve('bar', '1.2.3'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubGet(); final cache = path.join(d.sandbox, cachePath); @@ -34,9 +32,9 @@ test('running pub cache clean deletes cache only with confirmation', () async { - await servePackages((b) => b + await servePackages() ..serve('foo', '1.1.2') - ..serve('bar', '1.2.3')); + ..serve('bar', '1.2.3'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubGet(); final cache = path.join(d.sandbox, cachePath);
diff --git a/test/cache/list_test.dart b/test/cache/list_test.dart index 9d8b9f3..a2c26a4 100644 --- a/test/cache/list_test.dart +++ b/test/cache/list_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart';
diff --git a/test/cache/repair/empty_cache_test.dart b/test/cache/repair/empty_cache_test.dart index 679e32a..13d68cc 100644 --- a/test/cache/repair/empty_cache_test.dart +++ b/test/cache/repair/empty_cache_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart';
diff --git a/test/cache/repair/git_test.dart b/test/cache/repair/git_test.dart index abb0ab7..262343a 100644 --- a/test/cache/repair/git_test.dart +++ b/test/cache/repair/git_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart';
diff --git a/test/cache/repair/handles_corrupted_binstub_test.dart b/test/cache/repair/handles_corrupted_binstub_test.dart index b1c3556..0ca169f 100644 --- a/test/cache/repair/handles_corrupted_binstub_test.dart +++ b/test/cache/repair/handles_corrupted_binstub_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('handles a corrupted binstub script', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/cache/repair/handles_corrupted_global_lockfile_test.dart b/test/cache/repair/handles_corrupted_global_lockfile_test.dart index 3952871..9a9af05 100644 --- a/test/cache/repair/handles_corrupted_global_lockfile_test.dart +++ b/test/cache/repair/handles_corrupted_global_lockfile_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/cache/repair/handles_failure_test.dart b/test/cache/repair/handles_failure_test.dart index 8016d30..d5637ca 100644 --- a/test/cache/repair/handles_failure_test.dart +++ b/test/cache/repair/handles_failure_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -13,15 +11,14 @@ void main() { test('handles failure to reinstall some packages', () async { // Only serve two packages so repairing will have a failure. - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.5'); - }); + final server = await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.5'); // Set up a cache with some packages. await d.dir(cachePath, [ d.dir('hosted', [ - d.dir('localhost%58${globalServer.port}', [ + d.dir('localhost%58${server.port}', [ d.dir('foo-1.2.3', [d.libPubspec('foo', '1.2.3'), d.file('broken.txt')]), d.dir('foo-1.2.4', @@ -41,7 +38,7 @@ expect(pub.stderr, emits(startsWith('Failed to repair foo 1.2.4. Error:'))); expect( pub.stderr, - emits('Package doesn\'t exist ' + emits('Package not available ' '(Package foo has no version 1.2.4).')); expect(pub.stdout, emits('Reinstalled 2 packages.'));
diff --git a/test/cache/repair/handles_orphaned_binstub_test.dart b/test/cache/repair/handles_orphaned_binstub_test.dart index 4954121..0754496 100644 --- a/test/cache/repair/handles_orphaned_binstub_test.dart +++ b/test/cache/repair/handles_orphaned_binstub_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; import '../../test_pub.dart'; -const _ORPHANED_BINSTUB = ''' +const _orphanedBinstub = ''' #!/usr/bin/env sh # This file was created by pub v0.1.2-3. # Package: foo @@ -22,7 +20,7 @@ void main() { test('handles an orphaned binstub script', () async { await d.dir(cachePath, [ - d.dir('bin', [d.file(binStubName('script'), _ORPHANED_BINSTUB)]) + d.dir('bin', [d.file(binStubName('script'), _orphanedBinstub)]) ]).create(); await runPub(
diff --git a/test/cache/repair/hosted.dart b/test/cache/repair/hosted.dart index 23d839b..ec3786b 100644 --- a/test/cache/repair/hosted.dart +++ b/test/cache/repair/hosted.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -13,14 +11,13 @@ import '../../test_pub.dart'; void main() { - setUp(() { - return servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.4'); - builder.serve('foo', '1.2.5'); - builder.serve('bar', '1.2.3'); - builder.serve('bar', '1.2.4'); - }); + setUp(() async { + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.4') + ..serve('foo', '1.2.5') + ..serve('bar', '1.2.3') + ..serve('bar', '1.2.4'); }); test('reinstalls previously cached hosted packages', () async {
diff --git a/test/cache/repair/recompiles_snapshots_test.dart b/test/cache/repair/recompiles_snapshots_test.dart index 698e148..f3c3d6c 100644 --- a/test/cache/repair/recompiles_snapshots_test.dart +++ b/test/cache/repair/recompiles_snapshots_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('recompiles activated executable snapshots', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/cache/repair/updates_binstubs_test.dart b/test/cache/repair/updates_binstubs_test.dart index bfb6400..e8cbfb4 100644 --- a/test/cache/repair/updates_binstubs_test.dart +++ b/test/cache/repair/updates_binstubs_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; import '../../test_pub.dart'; -const _OUTDATED_BINSTUB = ''' +const _outdatedBinstub = ''' #!/usr/bin/env sh # This file was created by pub v0.1.2-3. # Package: foo @@ -21,19 +19,17 @@ void main() { test('updates an outdated binstub script', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'foo-script': 'script'} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'foo-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub(args: ['global', 'activate', 'foo']); await d.dir(cachePath, [ - d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)]) + d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)]) ]).create(); // Repair them.
diff --git a/test/dependency_override_test.dart b/test/dependency_override_test.dart index 3cac645..59f59e4 100644 --- a/test/dependency_override_test.dart +++ b/test/dependency_override_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -14,11 +12,10 @@ void main() { forBothPubGetAndUpgrade((command) { test('chooses best version matching override constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -30,13 +27,14 @@ await pubCommand(command); - await d.appPackagesFile({'foo': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + ]).validate(); }); test('treats override as implicit dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -47,18 +45,19 @@ await pubCommand(command); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); }); test('ignores other constraints on overridden package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - builder.serve('bar', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0') + ..serve('bar', '1.0.0', pubspec: { 'dependencies': {'foo': '5.0.0-nonexistent'} }); - }); await d.dir(appPath, [ d.pubspec({ @@ -70,14 +69,16 @@ await pubCommand(command); - await d.appPackagesFile({'foo': '2.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('ignores SDK constraints', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'environment': {'sdk': '5.6.7-fblthp'} - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'environment': {'sdk': '5.6.7-fblthp'} }); await d.dir(appPath, [ @@ -88,15 +89,15 @@ ]).create(); await pubCommand(command); - - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); }); test('warns about overridden dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('bar', '1.0.0'); await d .dir('baz', [d.libDir('baz'), d.libPubspec('baz', '0.0.1')]).create();
diff --git a/test/dependency_services/dependency_services_test.dart b/test/dependency_services/dependency_services_test.dart index d341df4..0ab5825 100644 --- a/test/dependency_services/dependency_services_test.dart +++ b/test/dependency_services/dependency_services_test.dart
@@ -1,39 +1,77 @@ // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; +import 'package:test_process/test_process.dart'; import '../descriptor.dart' as d; import '../golden_file.dart'; import '../test_pub.dart'; -Future<void> pipeline(String name, List<_PackageVersion> upgrades) async { +late String snapshot; +const _commandRunner = 'bin/dependency_services.dart'; + +String _filter(String input) { + return input + .replaceAll(p.toUri(d.sandbox).toString(), r'file://$SANDBOX') + .replaceAll(d.sandbox, r'$SANDBOX') + .replaceAll(Platform.pathSeparator, '/') + .replaceAll(Platform.operatingSystem, r'$OS') + .replaceAll(globalServer.port.toString(), r'$PORT'); +} + +/// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and appends the output to [buffer]. +Future<void> runDependencyServicesToBuffer( + List<String> args, + StringBuffer buffer, { + String? workingDirectory, + Map<String, String>? environment, + dynamic exitCode = 0, + String? stdin, +}) async { + final process = await TestProcess.start( + Platform.resolvedExecutable, + ['--enable-asserts', snapshot, ...args], + environment: { + ...getPubTestEnvironment(), + ...?environment, + }, + workingDirectory: workingDirectory ?? p.join(d.sandbox, appPath), + ); + if (stdin != null) { + process.stdin.write(stdin); + await process.stdin.flush(); + await process.stdin.close(); + } + await process.shouldExit(exitCode); + + buffer.writeln([ + '\$ $_commandRunner ${args.join(' ')}', + ...await process.stdout.rest.map(_filter).toList(), + ...await process.stderr.rest.map((e) => '[E] ${_filter(e)}').toList(), + ].join('\n')); + buffer.write('\n'); +} + +Future<void> pipeline( + String name, + List<_PackageVersion> upgrades, + GoldenTestContext context, +) async { final buffer = StringBuffer(); - await runPubIntoBuffer([ - '__experimental-dependency-services', - 'list', - ], buffer); - await runPubIntoBuffer([ - '__experimental-dependency-services', - 'report', - ], buffer); + await runDependencyServicesToBuffer(['list'], buffer); + await runDependencyServicesToBuffer(['report'], buffer); final input = json.encode({ - 'changes': upgrades, + 'dependencyChanges': upgrades, }); - await runPubIntoBuffer([ - '__experimental-dependency-services', - 'apply', - ], buffer, stdin: input); + await runDependencyServicesToBuffer(['apply'], buffer, stdin: input); void catIntoBuffer(String path) { buffer.writeln('$path:'); buffer.writeln(File(p.join(d.sandbox, path)).readAsStringSync()); @@ -41,19 +79,24 @@ catIntoBuffer(p.join(appPath, 'pubspec.yaml')); catIntoBuffer(p.join(appPath, 'pubspec.lock')); - expectMatchesGoldenFile( - // TODO: Consider if expectMatchesGoldenFile should replace localhost:<port> - buffer.toString().replaceAll(RegExp('localhost:\d+'), 'localhost:<port>'), - 'test/dependency_services/goldens/dependency_report_$name.txt', + context.expectNextSection( + buffer.toString().replaceAll(RegExp(r'localhost:\d+'), 'localhost:<port>'), ); } Future<void> main() async { - test('Removing transitive', () async { - await servePackages((builder) => builder + setUpAll(() async { + final tempDir = Directory.systemTemp.createTempSync(); + snapshot = p.join(tempDir.path, 'dependency_services.dart.snapshot'); + final r = Process.runSync( + Platform.resolvedExecutable, ['--snapshot=$snapshot', _commandRunner]); + expect(r.exitCode, 0, reason: r.stderr); + }); + testWithGolden('Removing transitive', (context) async { + (await servePackages()) ..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'}) ..serve('foo', '2.2.3') - ..serve('transitive', '1.0.0')); + ..serve('transitive', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -64,17 +107,21 @@ }) ]).create(); await pubGet(); - await pipeline('removing_transitive', [ - _PackageVersion('foo', Version.parse('2.2.3')), - _PackageVersion('transitive', null) - ]); + await pipeline( + 'removing_transitive', + [ + _PackageVersion('foo', Version.parse('2.2.3')), + _PackageVersion('transitive', null) + ], + context, + ); }); - test('Adding transitive', () async { - await servePackages((builder) => builder + testWithGolden('Adding transitive', (context) async { + (await servePackages()) ..serve('foo', '1.2.3') ..serve('foo', '2.2.3', deps: {'transitive': '^1.0.0'}) - ..serve('transitive', '1.0.0')); + ..serve('transitive', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -85,19 +132,23 @@ }) ]).create(); await pubGet(); - await pipeline('adding_transitive', [ - _PackageVersion('foo', Version.parse('2.2.3')), - _PackageVersion('transitive', Version.parse('1.0.0')) - ]); + await pipeline( + 'adding_transitive', + [ + _PackageVersion('foo', Version.parse('2.2.3')), + _PackageVersion('transitive', Version.parse('1.0.0')) + ], + context, + ); }); } class _PackageVersion { String name; - Version version; + Version? version; _PackageVersion(this.name, this.version); - Map<String, Object> toJson() => { + Map<String, Object?> toJson() => { 'name': name, 'version': version?.toString(), };
diff --git a/test/deps/executables_test.dart b/test/deps/executables_test.dart index f568511..ea864fd 100644 --- a/test/deps/executables_test.dart +++ b/test/deps/executables_test.dart
@@ -2,13 +2,6 @@ // 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. -// @dart=2.10 - -import 'package:pub/src/ascii_tree.dart' as tree; -import 'package:pub/src/io.dart'; -import 'package:test/test.dart'; - -import '../ascii_tree_test.dart'; import '../descriptor.dart' as d; import '../golden_file.dart'; import '../test_pub.dart'; @@ -16,31 +9,29 @@ const _validMain = 'main() {}'; const _invalidMain = 'main() {'; -Future<void> variations(String name) async { - final buffer = StringBuffer(); - buffer.writeln(stripColors( - tree.fromFiles(listDir(d.sandbox, recursive: true), baseDir: d.sandbox))); +extension on GoldenTestContext { + Future<void> runExecutablesTest() async { + await pubGet(); - await pubGet(); - await runPubIntoBuffer(['deps', '--executables'], buffer); - await runPubIntoBuffer(['deps', '--executables', '--dev'], buffer); - // The json ouput also lists the exectuables. - await runPubIntoBuffer(['deps', '--json'], buffer); - // The easiest way to update the golden files is to delete them and rerun the - // test. - expectMatchesGoldenFile(buffer.toString(), 'test/deps/goldens/$name.txt'); + await tree(); + + await run(['deps', '--executables']); + await run(['deps', '--executables', '--dev']); + await run(['deps', '--json']); + } } void main() { - test('skips non-Dart executables', () async { + testWithGolden('skips non-Dart executables', (ctx) async { await d.dir(appPath, [ d.appPubspec(), d.dir('bin', [d.file('foo.py'), d.file('bar.sh')]) ]).create(); - await variations('non_dart_executables'); + + await ctx.runExecutablesTest(); }); - test('lists Dart executables, even without entrypoints', () async { + testWithGolden('lists Dart executables, without entrypoints', (ctx) async { await d.dir(appPath, [ d.appPubspec(), d.dir( @@ -48,10 +39,11 @@ [d.file('foo.dart', _validMain), d.file('bar.dart', _invalidMain)], ) ]).create(); - await variations('dart_executables'); + + await ctx.runExecutablesTest(); }); - test('skips executables in sub directories', () async { + testWithGolden('skips executables in sub directories', (ctx) async { await d.dir(appPath, [ d.appPubspec(), d.dir('bin', [ @@ -59,10 +51,11 @@ d.dir('sub', [d.file('bar.dart', _validMain)]) ]) ]).create(); - await variations('nothing_in_sub_drectories'); + + await ctx.runExecutablesTest(); }); - test('lists executables from a dependency', () async { + testWithGolden('lists executables from a dependency', (ctx) async { await d.dir('foo', [ d.libPubspec('foo', '1.0.0'), d.dir('bin', [d.file('bar.dart', _validMain)]) @@ -74,10 +67,11 @@ }) ]).create(); - await variations('from_dependency'); + await ctx.runExecutablesTest(); }); - test('lists executables only from immediate dependencies', () async { + testWithGolden('lists executables only from immediate dependencies', + (ctx) async { await d.dir(appPath, [ d.appPubspec({ 'foo': {'path': '../foo'} @@ -96,10 +90,10 @@ d.dir('bin', [d.file('qux.dart', _validMain)]) ]).create(); - await variations('only_immediate'); + await ctx.runExecutablesTest(); }); - test('applies formatting before printing executables', () async { + testWithGolden('applies formatting before printing executables', (ctx) async { await d.dir(appPath, [ d.appPubspec({ 'foo': {'path': '../foo'}, @@ -119,10 +113,10 @@ d.dir('bin', [d.file('qux.dart', _validMain)]) ]).create(); - await variations('formatting'); + await ctx.runExecutablesTest(); }); - test('dev dependencies', () async { + testWithGolden('dev dependencies', (ctx) async { await d.dir('foo', [ d.libPubspec('foo', '1.0.0'), d.dir('bin', [d.file('bar.dart', _validMain)]) @@ -136,10 +130,11 @@ } }) ]).create(); - await variations('dev_dependencies'); + + await ctx.runExecutablesTest(); }); - test('overriden dependencies executables', () async { + testWithGolden('overriden dependencies executables', (ctx) async { await d.dir('foo-1.0', [ d.libPubspec('foo', '1.0.0'), d.dir('bin', [d.file('bar.dart', _validMain)]) @@ -162,6 +157,7 @@ } }) ]).create(); - await variations('overrides'); + + await ctx.runExecutablesTest(); }); }
diff --git a/test/deps/goldens/dart_executables.txt b/test/deps/goldens/dart_executables.txt deleted file mode 100644 index 9284ceb..0000000 --- a/test/deps/goldens/dart_executables.txt +++ /dev/null
@@ -1,36 +0,0 @@ -'-- myapp - |-- bin - | |-- bar.dart - | '-- foo.dart - '-- pubspec.yaml - -$ pub deps --executables -myapp: bar, foo - -$ pub deps --executables --dev -myapp: bar, foo - -$ pub deps --json -{ - "root": "myapp", - "packages": [ - { - "name": "myapp", - "version": "0.0.0", - "kind": "root", - "source": "root", - "dependencies": [] - } - ], - "sdks": [ - { - "name": "Dart", - "version": "0.1.2+3" - } - ], - "executables": [ - ":bar", - ":foo" - ] -} -
diff --git a/test/deps/goldens/from_dependency.txt b/test/deps/goldens/from_dependency.txt deleted file mode 100644 index 30836e5..0000000 --- a/test/deps/goldens/from_dependency.txt +++ /dev/null
@@ -1,45 +0,0 @@ -|-- foo -| |-- bin -| | '-- bar.dart -| '-- pubspec.yaml -'-- myapp - '-- pubspec.yaml - -$ pub deps --executables -foo:bar - -$ pub deps --executables --dev -foo:bar - -$ pub deps --json -{ - "root": "myapp", - "packages": [ - { - "name": "myapp", - "version": "0.0.0", - "kind": "root", - "source": "root", - "dependencies": [ - "foo" - ] - }, - { - "name": "foo", - "version": "1.0.0", - "kind": "direct", - "source": "path", - "dependencies": [] - } - ], - "sdks": [ - { - "name": "Dart", - "version": "0.1.2+3" - } - ], - "executables": [ - "foo:bar" - ] -} -
diff --git a/test/deps/goldens/non_dart_executables.txt b/test/deps/goldens/non_dart_executables.txt deleted file mode 100644 index 646e21e..0000000 --- a/test/deps/goldens/non_dart_executables.txt +++ /dev/null
@@ -1,31 +0,0 @@ -'-- myapp - |-- bin - | |-- bar.sh - | '-- foo.py - '-- pubspec.yaml - -$ pub deps --executables - -$ pub deps --executables --dev - -$ pub deps --json -{ - "root": "myapp", - "packages": [ - { - "name": "myapp", - "version": "0.0.0", - "kind": "root", - "source": "root", - "dependencies": [] - } - ], - "sdks": [ - { - "name": "Dart", - "version": "0.1.2+3" - } - ], - "executables": [] -} -
diff --git a/test/deps/goldens/nothing_in_sub_drectories.txt b/test/deps/goldens/nothing_in_sub_drectories.txt deleted file mode 100644 index db3c77c..0000000 --- a/test/deps/goldens/nothing_in_sub_drectories.txt +++ /dev/null
@@ -1,36 +0,0 @@ -'-- myapp - |-- bin - | |-- foo.dart - | '-- sub - | '-- bar.dart - '-- pubspec.yaml - -$ pub deps --executables -myapp:foo - -$ pub deps --executables --dev -myapp:foo - -$ pub deps --json -{ - "root": "myapp", - "packages": [ - { - "name": "myapp", - "version": "0.0.0", - "kind": "root", - "source": "root", - "dependencies": [] - } - ], - "sdks": [ - { - "name": "Dart", - "version": "0.1.2+3" - } - ], - "executables": [ - ":foo" - ] -} -
diff --git a/test/deps_test.dart b/test/deps_test.dart index 2d59ef8..7336f13 100644 --- a/test/deps_test.dart +++ b/test/deps_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -12,21 +10,19 @@ void main() { setUp(() async { - await servePackages((builder) { - builder.serve('normal', '1.2.3', - deps: {'transitive': 'any', 'circular_a': 'any'}); - builder.serve('transitive', '1.2.3', deps: {'shared': 'any'}); - builder.serve('shared', '1.2.3', deps: {'other': 'any'}); - builder.serve('dev_only', '1.2.3'); - builder.serve('unittest', '1.2.3', - deps: {'shared': 'any', 'dev_only': 'any'}); - builder.serve('other', '1.0.0', deps: {'myapp': 'any'}); - builder.serve('overridden', '1.0.0'); - builder.serve('overridden', '2.0.0'); - builder.serve('override_only', '1.2.3'); - builder.serve('circular_a', '1.2.3', deps: {'circular_b': 'any'}); - builder.serve('circular_b', '1.2.3', deps: {'circular_a': 'any'}); - }); + await servePackages() + ..serve('normal', '1.2.3', + deps: {'transitive': 'any', 'circular_a': 'any'}) + ..serve('transitive', '1.2.3', deps: {'shared': 'any'}) + ..serve('shared', '1.2.3', deps: {'other': 'any'}) + ..serve('dev_only', '1.2.3') + ..serve('unittest', '1.2.3', deps: {'shared': 'any', 'dev_only': 'any'}) + ..serve('other', '1.0.0', deps: {'myapp': 'any'}) + ..serve('overridden', '1.0.0') + ..serve('overridden', '2.0.0') + ..serve('override_only', '1.2.3') + ..serve('circular_a', '1.2.3', deps: {'circular_b': 'any'}) + ..serve('circular_b', '1.2.3', deps: {'circular_a': 'any'}); await d.dir('from_path', [d.libDir('from_path'), d.libPubspec('from_path', '1.2.3')]).create();
diff --git a/test/descriptor.dart b/test/descriptor.dart index 3eee5d1..ee50851 100644 --- a/test/descriptor.dart +++ b/test/descriptor.dart
@@ -2,12 +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. -// @dart=2.10 - /// Pub-specific test descriptors. import 'dart:convert'; -import 'package:meta/meta.dart'; import 'package:oauth2/oauth2.dart' as oauth2; import 'package:path/path.dart' as p; import 'package:pub/src/language_version.dart'; @@ -27,11 +24,11 @@ export 'descriptor/tar.dart'; /// Creates a new [GitRepoDescriptor] with [name] and [contents]. -GitRepoDescriptor git(String name, [Iterable<Descriptor> contents]) => +GitRepoDescriptor git(String name, [List<Descriptor>? contents]) => GitRepoDescriptor(name, contents ?? <Descriptor>[]); /// Creates a new [TarFileDescriptor] with [name] and [contents]. -TarFileDescriptor tar(String name, [Iterable<Descriptor> contents]) => +TarFileDescriptor tar(String name, [List<Descriptor>? contents]) => TarFileDescriptor(name, contents ?? <Descriptor>[]); /// Describes a package that passes all validation. @@ -67,14 +64,14 @@ /// /// [contents] may contain [Future]s that resolve to serializable objects, /// which may in turn contain [Future]s recursively. -Descriptor pubspec(Map<String, Object> contents) => YamlDescriptor( +Descriptor pubspec(Map<String, Object?> contents) => YamlDescriptor( 'pubspec.yaml', yaml({ ...contents, // TODO: Copy-pasting this into all call-sites, or use d.libPubspec 'environment': { 'sdk': '>=0.1.2 <1.0.0', - ...contents['environment'] as Map ?? {}, + ...(contents['environment'] ?? {}) as Map, }, }), ); @@ -84,8 +81,8 @@ /// Describes a file named `pubspec.yaml` for an application package with the /// given [dependencies]. -Descriptor appPubspec([Map dependencies]) { - var map = <String, dynamic>{ +Descriptor appPubspec([Map? dependencies]) { + var map = <String, Object>{ 'name': 'myapp', 'environment': { 'sdk': '>=0.1.2 <1.0.0', @@ -100,7 +97,7 @@ /// constraint on that version, otherwise it adds an SDK constraint allowing /// the current SDK version. Descriptor libPubspec(String name, String version, - {Map deps, Map devDeps, String sdk}) { + {Map? deps, Map? devDeps, String? sdk}) { var map = packageMap(name, version, deps, devDeps); if (sdk != null) { map['environment'] = {'sdk': sdk}; @@ -112,7 +109,7 @@ /// Describes a directory named `lib` containing a single dart file named /// `<name>.dart` that contains a line of Dart code. -Descriptor libDir(String name, [String code]) { +Descriptor libDir(String name, [String? code]) { // Default to printing the name if no other code was given. code ??= name; return dir('lib', [file('$name.dart', 'main() => "$code";')]); @@ -130,8 +127,8 @@ /// If [repoName] is not given it is assumed to be equal to [packageName]. Descriptor gitPackageRevisionCacheDir( String packageName, { - int modifier, - String repoName, + int? modifier, + String? repoName, }) { repoName = repoName ?? packageName; var value = packageName; @@ -159,7 +156,7 @@ /// validated since they will often lack the dependencies section that the /// real pubspec being compared against has. You usually only need to pass /// `true` for this if you plan to call [create] on the resulting descriptor. -Descriptor cacheDir(Map packages, {int port, bool includePubspecs = false}) { +Descriptor cacheDir(Map packages, {int? port, bool includePubspecs = false}) { var contents = <Descriptor>[]; packages.forEach((name, versions) { if (versions is! List) versions = [versions]; @@ -180,7 +177,7 @@ /// /// If [port] is passed, it's used as the port number of the local hosted server /// that this cache represents. It defaults to [globalServer.port]. -Descriptor hostedCache(Iterable<Descriptor> contents, {int port}) { +Descriptor hostedCache(Iterable<Descriptor> contents, {int? port}) { return dir(cachePath, [ dir('hosted', [dir('localhost%58${port ?? globalServer.port}', contents)]) ]); @@ -190,7 +187,7 @@ /// credentials. The URL "/token" on [server] will be used as the token /// endpoint for refreshing the access token. Descriptor credentialsFile(PackageServer server, String accessToken, - {String refreshToken, DateTime expiration}) { + {String? refreshToken, DateTime? expiration}) { return dir( configPath, [ @@ -208,7 +205,7 @@ } Descriptor legacyCredentialsFile(PackageServer server, String accessToken, - {String refreshToken, DateTime expiration}) { + {String? refreshToken, DateTime? expiration}) { return dir( cachePath, [ @@ -228,8 +225,8 @@ String _credentialsFileContent( PackageServer server, String accessToken, { - String refreshToken, - DateTime expiration, + String? refreshToken, + DateTime? expiration, }) => oauth2.Credentials( accessToken, @@ -245,14 +242,12 @@ /// Describes the file in the system cache that contains credentials for /// third party hosted pub servers. Descriptor tokensFile([Map<String, dynamic> contents = const {}]) { - return dir(configPath, [ - file('pub-tokens.json', contents != null ? jsonEncode(contents) : null) - ]); + return dir(configPath, [file('pub-tokens.json', jsonEncode(contents))]); } /// Describes the application directory, containing only a pubspec specifying /// the given [dependencies]. -DirectoryDescriptor appDir([Map dependencies]) => +DirectoryDescriptor appDir([Map? dependencies]) => dir(appPath, [appPubspec(dependencies)]); /// Describes a `.packages` file. @@ -266,7 +261,7 @@ /// entries (one per key in [dependencies]), each with a path that contains /// either the version string (for a reference to the pub cache) or a /// path to a path dependency, relative to the application directory. -Descriptor packagesFile([Map<String, String> dependencies]) => +Descriptor packagesFile(Map<String, String> dependencies) => PackagesFileDescriptor(dependencies); /// Describes a `.dart_tools/package_config.json` file. @@ -282,13 +277,31 @@ }) => PackageConfigFileDescriptor(packages, generatorVersion); +Descriptor appPackageConfigFile( + List<PackageConfigEntry> packages, { + String generatorVersion = '0.1.2+3', +}) => + dir( + appPath, + [ + packageConfigFile( + [ + packageConfigEntry(name: 'myapp', path: '.'), + ...packages, + ], + generatorVersion: generatorVersion, + ), + ], + ); + /// Create a [PackageConfigEntry] which assumes package with [name] is either /// a cached package with given [version] or a path dependency at given [path]. PackageConfigEntry packageConfigEntry({ - @required String name, - String version, - String path, - String languageVersion, + required String name, + String? version, + String? path, + String? languageVersion, + PackageServer? server, }) { if (version != null && path != null) { throw ArgumentError.value( @@ -300,7 +313,7 @@ } Uri rootUri; if (version != null) { - rootUri = p.toUri(globalPackageServer.pathInCache(name, version)); + rootUri = p.toUri((server ?? globalServer).pathInCache(name, version)); } else { rootUri = p.toUri(p.join('..', path)); }
diff --git a/test/descriptor/git.dart b/test/descriptor/git.dart index 56cd59f..edfc7bd 100644 --- a/test/descriptor/git.dart +++ b/test/descriptor/git.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'package:path/path.dart' as path; @@ -17,7 +15,7 @@ /// Creates the Git repository and commits the contents. @override - Future create([String parent]) async { + Future create([String? parent]) async { await super.create(parent); await _runGitCommands(parent, [ ['init'], @@ -35,7 +33,7 @@ /// the previous structure to the Git repo. /// /// [parent] defaults to [sandbox]. - Future commit([String parent]) async { + Future commit([String? parent]) async { await super.create(parent); await _runGitCommands(parent, [ ['add', '.'], @@ -47,7 +45,7 @@ /// referred to by [ref]. /// /// [parent] defaults to [sandbox]. - Future<String> revParse(String ref, [String parent]) async { + Future<String> revParse(String ref, [String? parent]) async { var output = await _runGit(['rev-parse', ref], parent); return output[0]; } @@ -55,9 +53,9 @@ /// Runs a Git command in this repository. /// /// [parent] defaults to [sandbox]. - Future runGit(List<String> args, [String parent]) => _runGit(args, parent); + Future runGit(List<String> args, [String? parent]) => _runGit(args, parent); - Future<List<String>> _runGit(List<String> args, String parent) { + Future<List<String>> _runGit(List<String> args, String? parent) { // Explicitly specify the committer information. Git needs this to commit // and we don't want to rely on the buildbots having this already set up. var environment = { @@ -72,7 +70,7 @@ environment: environment); } - Future _runGitCommands(String parent, List<List<String>> commands) async { + Future _runGitCommands(String? parent, List<List<String>> commands) async { for (var command in commands) { await _runGit(command, parent); }
diff --git a/test/descriptor/packages.dart b/test/descriptor/packages.dart index 2a23e40..b670322 100644 --- a/test/descriptor/packages.dart +++ b/test/descriptor/packages.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async' show Future; import 'dart:convert' show JsonEncoder, json, utf8; import 'dart:io' show File; @@ -25,7 +23,7 @@ /// Describes a `.packages` file and its contents. class PackagesFileDescriptor extends Descriptor { /// A map from package names to either version strings or path to the package. - final Map<String, String> _dependencies; + final Map<String, String>? _dependencies; /// Describes a `.packages` file with the given dependencies. /// @@ -34,11 +32,12 @@ PackagesFileDescriptor([this._dependencies]) : super('.packages'); @override - Future create([String parent]) { + Future create([String? parent]) { var contents = const <int>[]; - if (_dependencies != null) { + var dependencies = _dependencies; + if (dependencies != null) { var mapping = <String, Uri>{}; - _dependencies.forEach((package, version) { + dependencies.forEach((package, version) { String packagePath; if (_isSemver(version)) { // It's a cache reference. @@ -58,7 +57,7 @@ } @override - Future validate([String parent]) async { + Future validate([String? parent]) async { var fullPath = p.join(parent ?? sandbox, name); if (!await File(fullPath).exists()) { fail("File not found: '$fullPath'."); @@ -68,14 +67,16 @@ var map = packages_file.parse(bytes, Uri.parse(_base)); - for (var package in _dependencies.keys) { + var dependencies = _dependencies!; + + for (var package in dependencies.keys) { if (!map.containsKey(package)) { fail('.packages does not contain $package entry'); } - var description = _dependencies[package]; + var description = dependencies[package]!; if (_isSemver(description)) { - if (!map[package].path.contains(description)) { + if (!map[package]!.path.contains(description)) { fail('.packages of $package has incorrect version. ' 'Expected $description, found location: ${map[package]}.'); } @@ -90,9 +91,9 @@ } } - if (map.length != _dependencies.length) { + if (map.length != dependencies.length) { for (var key in map.keys) { - if (!_dependencies.containsKey(key)) { + if (!dependencies.containsKey(key)) { fail('.packages file contains unexpected entry: $key'); } } @@ -128,7 +129,7 @@ : super('.dart_tool/package_config.json'); @override - Future<void> create([String parent]) async { + Future<void> create([String? parent]) async { final packageConfigFile = File(p.join(parent ?? sandbox, name)); await packageConfigFile.parent.create(); await packageConfigFile.writeAsString( @@ -137,13 +138,13 @@ } @override - Future<void> validate([String parent]) async { + Future<void> validate([String? parent]) async { final packageConfigFile = p.join(parent ?? sandbox, name); if (!await File(packageConfigFile).exists()) { fail("File not found: '$packageConfigFile'."); } - Map<String, Object> rawJson = json.decode( + Map<String, dynamic> rawJson = json.decode( await File(packageConfigFile).readAsString(), ); PackageConfig config; @@ -155,10 +156,20 @@ // Compare packages as sets to ignore ordering. expect( - config.packages.map((e) => e.toJson()).toSet(), - equals(_packages.map((e) => e.toJson()).toSet()), - reason: - '"packages" property in "$packageConfigFile" does not expected values', + config.packages, + _packages + .map( + (p) => isA<PackageConfigEntry>() + .having((p0) => p0.name, 'name', p.name) + .having( + (p0) => p0.languageVersion, + 'languageVersion', + // If the expected entry has no language-version we don't check it. + p.languageVersion ?? anything) + .having((p0) => p0.rootUri, 'rootUri', p.rootUri) + .having((p0) => p0.packageUri, 'packageUri', p.packageUri), + ) + .toSet(), ); final expected = PackageConfig.fromJson(_config.toJson());
diff --git a/test/descriptor/tar.dart b/test/descriptor/tar.dart index 1c4f89f..2a3488f 100644 --- a/test/descriptor/tar.dart +++ b/test/descriptor/tar.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; @@ -23,7 +21,7 @@ /// Creates the files and directories within this tar file, then archives /// them, compresses them, and saves the result to [parentDir]. @override - Future create([String parent]) { + Future create([String? parent]) { return withTempDir((tempDir) async { await Future.wait(contents.map((entry) => entry.create(tempDir))); @@ -41,7 +39,7 @@ /// Validates that the `.tar.gz` file at [path] contains the expected /// contents. @override - Future validate([String parent]) { + Future validate([String? parent]) { throw UnimplementedError('TODO(nweiz): implement this'); }
diff --git a/test/descriptor/yaml.dart b/test/descriptor/yaml.dart index 086da84..6840041 100644 --- a/test/descriptor/yaml.dart +++ b/test/descriptor/yaml.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async' show Future; import 'dart:convert' show utf8; import 'dart:io'; @@ -29,7 +27,7 @@ Stream.fromIterable([utf8.encode(_contents)]); @override - Future validate([String parent]) async { + Future validate([String? parent]) async { var fullPath = p.join(parent ?? sandbox, name); if (!await File(fullPath).exists()) { fail("File not found: '$fullPath'.");
diff --git a/test/descriptor_server.dart b/test/descriptor_server.dart deleted file mode 100644 index a023518..0000000 --- a/test/descriptor_server.dart +++ /dev/null
@@ -1,142 +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. - -// @dart=2.10 - -import 'dart:async'; - -import 'package:path/path.dart' as p; -import 'package:shelf/shelf.dart' as shelf; -import 'package:shelf/shelf_io.dart' as shelf_io; -import 'package:test/test.dart' hide fail; - -import 'descriptor.dart' as d; - -/// The global [DescriptorServer] that's used by default. -/// -/// `null` if there's no global server in use. This can be set to replace the -/// existing global server. -DescriptorServer get globalServer => _globalServer; -set globalServer(DescriptorServer value) { - if (_globalServer == null) { - addTearDown(() { - _globalServer = null; - }); - } else { - expect(_globalServer.close(), completes); - } - - _globalServer = value; -} - -DescriptorServer _globalServer; - -/// Creates a global [DescriptorServer] to serve [contents] as static files. -/// -/// This server will exist only for the duration of the pub run. It's accessible -/// via [server]. Subsequent calls to [serve] replace the previous server. -Future serve([List<d.Descriptor> contents]) async { - globalServer = (await DescriptorServer.start())..contents.addAll(contents); -} - -class DescriptorServer { - /// The underlying server. - final shelf.Server _server; - - /// A future that will complete to the port used for the server. - int get port => _server.url.port; - - /// The list of paths that have been requested from this server. - final requestedPaths = <String>[]; - - /// The base directory descriptor of the directories served by [this]. - final d.DirectoryDescriptor _baseDir; - - /// The descriptors served by this server. - /// - /// This can safely be modified between requests. - List<d.Descriptor> get contents => _baseDir.contents; - - /// Handlers for requests not easily described as files. - final Map<Pattern, shelf.Handler> extraHandlers = {}; - - /// Creates an HTTP server to serve [contents] as static files. - /// - /// This server exists only for the duration of the pub run. Subsequent calls - /// to [serve] replace the previous server. - static Future<DescriptorServer> start() async => - DescriptorServer._(await shelf_io.IOServer.bind('localhost', 0)); - - /// Creates a server that reports an error if a request is ever received. - static Future<DescriptorServer> errors() async => - DescriptorServer._(await shelf_io.IOServer.bind('localhost', 0)); - - DescriptorServer._(this._server) : _baseDir = d.dir('serve-dir', []) { - _server.mount((request) async { - final pathWithInitialSlash = '/${request.url.path}'; - final key = extraHandlers.keys.firstWhere((pattern) { - final match = pattern.matchAsPrefix(pathWithInitialSlash); - return match != null && match.end == pathWithInitialSlash.length; - }, orElse: () => null); - if (key != null) return extraHandlers[key](request); - - var path = p.posix.fromUri(request.url.path); - requestedPaths.add(path); - - try { - var stream = await _validateStream(_baseDir.load(path)); - return shelf.Response.ok(stream); - } catch (_) { - return shelf.Response.notFound('File "$path" not found.'); - } - }); - addTearDown(_server.close); - } - - /// Closes this server. - Future close() => _server.close(); -} - -/// Ensures that [stream] can emit at least one value successfully (or close -/// without any values). -/// -/// For example, reading asynchronously from a non-existent file will return a -/// stream that fails on the first chunk. In order to handle that more -/// gracefully, you may want to check that the stream looks like it's working -/// before you pipe the stream to something else. -/// -/// This lets you do that. It returns a [Future] that completes to a [Stream] -/// emitting the same values and errors as [stream], but only if at least one -/// value can be read successfully. If an error occurs before any values are -/// emitted, the returned Future completes to that error. -Future<Stream<T>> _validateStream<T>(Stream<T> stream) { - var completer = Completer<Stream<T>>(); - var controller = StreamController<T>(sync: true); - - StreamSubscription subscription; - subscription = stream.listen((value) { - // We got a value, so the stream is valid. - if (!completer.isCompleted) completer.complete(controller.stream); - controller.add(value); - }, onError: (error, [StackTrace stackTrace]) { - // If the error came after values, it's OK. - if (completer.isCompleted) { - controller.addError(error, stackTrace); - return; - } - - // Otherwise, the error came first and the stream is invalid. - completer.completeError(error, stackTrace); - - // We won't be returning the stream at all in this case, so unsubscribe - // and swallow the error. - subscription.cancel(); - }, onDone: () { - // It closed with no errors, so the stream is valid. - if (!completer.isCompleted) completer.complete(controller.stream); - controller.close(); - }); - - return completer.future; -}
diff --git a/test/dev_dependency_test.dart b/test/dev_dependency_test.dart index 471f53c..b192444 100644 --- a/test/dev_dependency_test.dart +++ b/test/dev_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import 'descriptor.dart' as d; @@ -29,7 +27,10 @@ await pubGet(); - await d.appPackagesFile({'foo': '../foo', 'bar': '../bar'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + d.packageConfigEntry(name: 'bar', path: '../bar'), + ]).validate(); }); test("includes dev dependency's transitive dependencies", () async { @@ -54,7 +55,10 @@ await pubGet(); - await d.appPackagesFile({'foo': '../foo', 'bar': '../bar'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + d.packageConfigEntry(name: 'bar', path: '../bar'), + ]).validate(); }); test("ignores transitive dependency's dev dependencies", () async { @@ -80,6 +84,8 @@ await pubGet(); - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); }); }
diff --git a/test/directory_option_test.dart b/test/directory_option_test.dart index c993200..65193bf 100644 --- a/test/directory_option_test.dart +++ b/test/directory_option_test.dart
@@ -2,33 +2,33 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:path/path.dart' as p; import 'package:shelf/shelf.dart' as shelf; -import 'package:test/test.dart'; import 'descriptor.dart'; import 'golden_file.dart'; import 'test_pub.dart'; Future<void> main() async { - test('commands taking a --directory/-C parameter work', () async { - await servePackages((b) => b + testWithGolden('commands taking a --directory/-C parameter work', + (ctx) async { + await servePackages() ..serve('foo', '1.0.0') ..serve('foo', '0.1.2') - ..serve('bar', '1.2.3')); - await credentialsFile(globalPackageServer, 'access token').create(); - globalPackageServer - .extraHandlers[RegExp('/api/packages/test_pkg/uploaders')] = (request) { - return shelf.Response.ok( - jsonEncode({ - 'success': {'message': 'Good job!'} - }), - headers: {'content-type': 'application/json'}); - }; + ..serve('bar', '1.2.3'); + await credentialsFile(globalServer, 'access token').create(); + globalServer.handle( + RegExp('/api/packages/test_pkg/uploaders'), + (request) { + return shelf.Response.ok( + jsonEncode({ + 'success': {'message': 'Good job!'} + }), + headers: {'content-type': 'application/json'}); + }, + ); await validPackage.create(); await dir(appPath, [ @@ -56,42 +56,34 @@ }) ]), ]).create(); - final buffer = StringBuffer(); - Future<void> run(List<String> args) async { - await runPubIntoBuffer( - args, - buffer, + + final cases = [ + // Try --directory after command. + ['add', '--directory=$appPath', 'foo'], + // Try the top-level version also. + ['-C', appPath, 'add', 'bar'], + // When both top-level and after command, the one after command takes + // precedence. + ['-C', p.join(appPath, 'example'), 'get', '--directory=$appPath', 'bar'], + ['remove', 'bar', '-C', appPath], + ['get', 'bar', '-C', appPath], + ['get', 'bar', '-C', '$appPath/example'], + ['get', 'bar', '-C', '$appPath/example2'], + ['get', 'bar', '-C', '$appPath/broken_dir'], + ['downgrade', '-C', appPath], + ['upgrade', 'bar', '-C', appPath], + ['run', '-C', appPath, 'bin/app.dart'], + ['publish', '-C', appPath, '--dry-run'], + ['uploader', '-C', appPath, 'add', 'sigurdm@google.com'], + ['deps', '-C', appPath], + ]; + + for (var i = 0; i < cases.length; i++) { + await ctx.run( + cases[i], workingDirectory: sandbox, environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}, ); } - - await run(['add', '--directory=$appPath', 'foo']); - // Try the top-level version also. - await run(['-C', appPath, 'add', 'bar']); - // When both top-level and after command, the one after command takes - // precedence. - await run([ - '-C', - p.join(appPath, 'example'), - 'get', - '--directory=$appPath', - 'bar', - ]); - await run(['remove', 'bar', '-C', appPath]); - await run(['get', 'bar', '-C', appPath]); - await run(['get', 'bar', '-C', '$appPath/example']); - await run(['get', 'bar', '-C', '$appPath/example2']); - await run(['get', 'bar', '-C', '$appPath/broken_dir']); - await run(['downgrade', '-C', appPath]); - await run(['upgrade', 'bar', '-C', appPath]); - await run(['run', '-C', appPath, 'bin/app.dart']); - await run(['publish', '-C', appPath, '--dry-run']); - await run(['uploader', '-C', appPath, 'add', 'sigurdm@google.com']); - await run(['deps', '-C', appPath]); - // TODO(sigurdm): we should also test `list-package-dirs` - it is a bit - // hard on windows due to quoted back-slashes on windows. - expectMatchesGoldenFile( - buffer.toString(), 'test/goldens/directory_option.txt'); }); }
diff --git a/test/downgrade/does_not_show_other_versions_test.dart b/test/downgrade/does_not_show_other_versions_test.dart index 485debb..884bbaf 100644 --- a/test/downgrade/does_not_show_other_versions_test.dart +++ b/test/downgrade/does_not_show_other_versions_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('does not show how many other versions are available', () async { - await servePackages((builder) { - builder.serve('downgraded', '1.0.0'); - builder.serve('downgraded', '2.0.0'); - builder.serve('downgraded', '3.0.0-dev'); - }); + await servePackages() + ..serve('downgraded', '1.0.0') + ..serve('downgraded', '2.0.0') + ..serve('downgraded', '3.0.0-dev'); await d.appDir({'downgraded': '3.0.0-dev'}).create();
diff --git a/test/downgrade/doesnt_change_git_dependencies_test.dart b/test/downgrade/doesnt_change_git_dependencies_test.dart index 41f0a51..1450af5 100644 --- a/test/downgrade/doesnt_change_git_dependencies_test.dart +++ b/test/downgrade/doesnt_change_git_dependencies_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/downgrade/dry_run_does_not_apply_changes_test.dart b/test/downgrade/dry_run_does_not_apply_changes_test.dart index 765cb35..38fbebe 100644 --- a/test/downgrade/dry_run_does_not_apply_changes_test.dart +++ b/test/downgrade/dry_run_does_not_apply_changes_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -13,10 +11,9 @@ void main() { test('--dry-run shows report but does not apply changes', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0'); // Create the first lockfile. await d.appDir({'foo': '2.0.0'}).create();
diff --git a/test/downgrade/unlock_if_necessary_test.dart b/test/downgrade/unlock_if_necessary_test.dart index b8aa83e..c8b55af 100644 --- a/test/downgrade/unlock_if_necessary_test.dart +++ b/test/downgrade/unlock_if_necessary_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -13,24 +11,27 @@ test( "downgrades one locked hosted package's dependencies if it's " 'necessary', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0', deps: {'foo_dep': 'any'}); - builder.serve('foo_dep', '2.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '2.0.0', deps: {'foo_dep': 'any'}); + server.serve('foo_dep', '2.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '2.0.0', 'foo_dep': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'foo_dep', version: '2.0.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '1.0.0', deps: {'foo_dep': '<2.0.0'}); - builder.serve('foo_dep', '1.0.0'); - }); + server.serve('foo', '1.0.0', deps: {'foo_dep': '<2.0.0'}); + server.serve('foo_dep', '1.0.0'); await pubDowngrade(args: ['foo']); - await d.appPackagesFile({'foo': '1.0.0', 'foo_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'foo_dep', version: '1.0.0'), + ]).validate(); }); }
diff --git a/test/downgrade/unlock_single_package_test.dart b/test/downgrade/unlock_single_package_test.dart index 73c3467..1188e41 100644 --- a/test/downgrade/unlock_single_package_test.dart +++ b/test/downgrade/unlock_single_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -11,51 +9,60 @@ void main() { test('can unlock a single package only in downgrade', () async { - await servePackages((builder) { - builder.serve('foo', '2.1.0', deps: {'bar': '>1.0.0'}); - builder.serve('bar', '2.1.0'); - }); + final server = await servePackages(); + server.serve('foo', '2.1.0', deps: {'bar': '>1.0.0'}); + server.serve('bar', '2.1.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.1.0'), + d.packageConfigEntry(name: 'bar', version: '2.1.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '1.0.0'); - }); + server.serve('foo', '1.0.0', deps: {'bar': 'any'}); + server.serve('bar', '1.0.0'); await pubDowngrade(args: ['bar']); - await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.1.0'), + d.packageConfigEntry(name: 'bar', version: '2.1.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '2.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '2.0.0'); - }); + server.serve('foo', '2.0.0', deps: {'bar': 'any'}); + server.serve('bar', '2.0.0'); await pubDowngrade(args: ['bar']); - await d.appPackagesFile({'foo': '2.1.0', 'bar': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.1.0'), + d.packageConfigEntry(name: 'bar', version: '2.0.0'), + ]).validate(); await pubDowngrade(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('will not downgrade below constraint #2629', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '2.1.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '2.1.0'); await d.appDir({'foo': '^2.0.0'}).create(); await pubGet(); - - await d.appPackagesFile({'foo': '2.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.1.0'), + ]).validate(); await pubDowngrade(args: ['foo']); - await d.appPackagesFile({'foo': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/embedding/embedding_test.dart b/test/embedding/embedding_test.dart index 257bf4b..a9795ea 100644 --- a/test/embedding/embedding_test.dart +++ b/test/embedding/embedding_test.dart
@@ -2,102 +2,329 @@ // 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. -// @dart=2.10 - +import 'dart:convert'; import 'dart:io'; import 'package:path/path.dart' as path; +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:test_process/test_process.dart'; + import '../descriptor.dart' as d; import '../golden_file.dart'; import '../test_pub.dart'; -const _command_runner = 'tool/test-bin/pub_command_runner.dart'; +const _commandRunner = 'tool/test-bin/pub_command_runner.dart'; -String snapshot; +late String snapshot; + +final logFile = p.join(d.sandbox, cachePath, 'log', 'pub_log.txt'); /// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and appends the output to [buffer]. -Future<void> runEmbedding(List<String> args, StringBuffer buffer, - {String workingDirextory, - Map<String, String> environment, - dynamic exitCode = 0}) async { +Future<void> runEmbeddingToBuffer( + List<String> args, + StringBuffer buffer, { + String? workingDirectory, + Map<String, String>? environment, + dynamic exitCode = 0, +}) async { final process = await TestProcess.start( Platform.resolvedExecutable, - [snapshot, ...args], - environment: environment, - workingDirectory: workingDirextory, + ['--enable-asserts', snapshot, ...args], + environment: { + ...getPubTestEnvironment(), + ...?environment, + }, + workingDirectory: workingDirectory, ); await process.shouldExit(exitCode); buffer.writeln([ - '\$ $_command_runner ${args.join(' ')}', - ...await process.stdout.rest.toList(), + '\$ $_commandRunner ${args.join(' ')}', + ...await process.stdout.rest.map(_filter).toList(), + ...await process.stderr.rest.map((e) => '[E] ${_filter(e)}').toList(), ].join('\n')); - final stdErr = await process.stderr.rest.toList(); - if (stdErr.isNotEmpty) { - buffer.writeln(stdErr.map((e) => '[E] $e').join('\n')); - } buffer.write('\n'); } +extension on GoldenTestContext { + /// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and compare to + /// next section in golden file. + Future<void> runEmbedding( + List<String> args, { + String? workingDirectory, + Map<String, String>? environment, + dynamic exitCode = 0, + }) async { + final buffer = StringBuffer(); + await runEmbeddingToBuffer( + args, + buffer, + workingDirectory: workingDirectory, + environment: environment, + exitCode: exitCode, + ); + + expectNextSection(buffer.toString()); + } +} + Future<void> main() async { setUpAll(() async { final tempDir = Directory.systemTemp.createTempSync(); snapshot = path.join(tempDir.path, 'command_runner.dart.snapshot'); final r = Process.runSync( - Platform.resolvedExecutable, ['--snapshot=$snapshot', _command_runner]); + Platform.resolvedExecutable, ['--snapshot=$snapshot', _commandRunner]); expect(r.exitCode, 0, reason: r.stderr); }); tearDownAll(() { File(snapshot).parent.deleteSync(recursive: true); }); - test('help text', () async { - final buffer = StringBuffer(); - await runEmbedding([''], buffer, exitCode: 64); - await runEmbedding(['--help'], buffer); - await runEmbedding(['pub'], buffer, exitCode: 64); - await runEmbedding(['pub', '--help'], buffer); - await runEmbedding(['pub', 'get', '--help'], buffer); - await runEmbedding(['pub', 'global'], buffer, exitCode: 64); - expectMatchesGoldenFile( - buffer.toString(), 'test/embedding/goldens/helptext.txt'); - }); - test('run works, though hidden', () async { - final buffer = StringBuffer(); + testWithGolden('run works, though hidden', (ctx) async { + await servePackages(); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', 'environment': { - 'sdk': '>=2.0.0 <3.0.0', + 'sdk': '0.1.2+3', }, }), d.dir('bin', [ d.file('main.dart', ''' import 'dart:io'; main() { - print("Hi"); + print('Hi'); exit(123); } ''') ]), ]).create(); - await runEmbedding( + await ctx.runEmbedding( ['pub', 'get'], - buffer, - workingDirextory: d.path(appPath), + workingDirectory: d.path(appPath), ); - await runEmbedding( + await ctx.runEmbedding( ['pub', 'run', 'bin/main.dart'], - buffer, exitCode: 123, - workingDirextory: d.path(appPath), - ); - expectMatchesGoldenFile( - buffer.toString(), - 'test/embedding/goldens/run.txt', + workingDirectory: d.path(appPath), ); }); + + testWithGolden( + 'logfile is written with --verbose and on unexpected exceptions', + (context) async { + final server = await servePackages(); + server.serve('foo', '1.0.0'); + await d.appDir({'foo': 'any'}).create(); + + // TODO(sigurdm) This logs the entire verbose trace to a golden file. + // + // This is fragile, and can break for all sorts of small reasons. We think + // this might be worth while having to have at least minimal testing of the + // verbose stack trace. + // + // But if you, future contributor, think this test is annoying: feel free to + // remove it, or rewrite it to filter out the stack-trace itself, only + // testing for creation of the file. + // + // It is a fragile test, and we acknowledge that it's usefulness can be + // debated... + await context.runEmbedding( + ['pub', '--verbose', 'get'], + workingDirectory: d.path(appPath), + ); + context.expectNextSection( + _filter( + File(logFile).readAsStringSync(), + ), + ); + await d.dir('empty').create(); + await context.runEmbedding( + ['pub', 'fail'], + workingDirectory: d.path('empty'), + exitCode: 1, + ); + context.expectNextSection( + _filter( + File(logFile).readAsStringSync(), + ), + ); + }); + + test('analytics', () async { + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('bar', '1.0.0'); + await d.dir('dep', [ + d.pubspec({ + 'name': 'dep', + 'environment': {'sdk': '>=0.0.0 <3.0.0'} + }) + ]).create(); + final app = d.dir(appPath, [ + d.appPubspec({ + 'foo': '1.0.0', + // The path dependency should not go to analytics. + 'dep': {'path': '../dep'} + }) + ]); + await app.create(); + + final buffer = StringBuffer(); + + await runEmbeddingToBuffer( + ['pub', 'get'], + buffer, + workingDirectory: app.io.path, + environment: {...getPubTestEnvironment(), '_PUB_LOG_ANALYTICS': 'true'}, + ); + final analytics = buffer + .toString() + .split('\n') + .where((line) => line.startsWith('[E] [analytics]: ')) + .map((line) => json.decode(line.substring('[E] [analytics]: '.length))); + expect(analytics, { + { + 'hitType': 'event', + 'message': { + 'category': 'pub-get', + 'action': 'foo', + 'label': '1.0.0', + 'value': 1, + 'cd1': 'direct', + 'ni': '1', + } + }, + { + 'hitType': 'event', + 'message': { + 'category': 'pub-get', + 'action': 'bar', + 'label': '1.0.0', + 'value': 1, + 'cd1': 'transitive', + 'ni': '1', + } + }, + { + 'hitType': 'timing', + 'message': { + 'variableName': 'resolution', + 'time': isA<int>(), + 'category': 'pub-get', + 'label': null + } + }, + }); + // Don't write the logs to file on a normal run. + expect(File(logFile).existsSync(), isFalse); + }); + + test('`embedding --verbose pub` is verbose', () async { + await servePackages(); + final buffer = StringBuffer(); + await runEmbeddingToBuffer(['--verbose', 'pub', 'logout'], buffer); + expect(buffer.toString(), contains('FINE: Pub 0.1.2+3')); + }); +} + +String _filter(String input) { + return input + .replaceAll(p.toUri(d.sandbox).toString(), r'file://$SANDBOX') + .replaceAll(d.sandbox, r'$SANDBOX') + .replaceAll(Platform.pathSeparator, '/') + .replaceAll(Platform.operatingSystem, r'$OS') + .replaceAll(globalServer.port.toString(), r'$PORT') + .replaceAll( + RegExp(r'^Created:(.*)$', multiLine: true), + r'Created: $TIME', + ) + .replaceAll( + RegExp(r'Generated by pub on (.*)$', multiLine: true), + r'Generated by pub on $TIME', + ) + .replaceAll( + RegExp(r'X-Pub-Session-ID(.*)$', multiLine: true), + r'X-Pub-Session-ID: $ID', + ) + .replaceAll( + RegExp(r'took (.*)$', multiLine: true), + r'took: $TIME', + ) + .replaceAll( + RegExp(r'date: (.*)$', multiLine: true), + r'date: $TIME', + ) + .replaceAll( + RegExp(r'Creating (.*) from stream\.$', multiLine: true), + r'Creating $FILE from stream', + ) + .replaceAll( + RegExp(r'Created (.*) from stream\.$', multiLine: true), + r'Created $FILE from stream', + ) + .replaceAll( + RegExp(r'Renaming directory $SANDBOX/cache/_temp/(.*?) to', + multiLine: true), + r'Renaming directory $SANDBOX/cache/_temp/', + ) + .replaceAll( + RegExp(r'Extracting .tar.gz stream to (.*?)$', multiLine: true), + r'Extracting .tar.gz stream to $DIR', + ) + .replaceAll( + RegExp(r'Extracted .tar.gz to (.*?)$', multiLine: true), + r'Extracted .tar.gz to $DIR', + ) + .replaceAll( + RegExp(r'Reading binary file (.*?)$', multiLine: true), + r'Reading binary file $FILE.', + ) + .replaceAll( + RegExp(r'Deleting directory (.*)$', multiLine: true), + r'Deleting directory $DIR', + ) + .replaceAll( + RegExp(r'Deleting directory (.*)$', multiLine: true), + r'Deleting directory $DIR', + ) + .replaceAll( + RegExp(r'Resolving dependencies finished (.*)$', multiLine: true), + r'Resolving dependencies finished ($TIME)', + ) + .replaceAll( + RegExp(r'Created temp directory (.*)$', multiLine: true), + r'Created temp directory $DIR', + ) + .replaceAll( + RegExp(r'Renaming directory (.*)$', multiLine: true), + r'Renaming directory $A to $B', + ) + .replaceAll( + RegExp(r'"_fetchedAt":"(.*)"}$', multiLine: true), + r'"_fetchedAt": "$TIME"}', + ) + .replaceAll( + RegExp(r'"generated": "(.*)",$', multiLine: true), + r'"generated": "$TIME",', + ) + .replaceAll( + RegExp(r'( |^)(/|[A-Z]:)(.*)/tool/test-bin/pub_command_runner.dart', + multiLine: true), + r' tool/test-bin/pub_command_runner.dart', + ) + .replaceAll( + RegExp(r'[ ]{4,}', multiLine: true), + r' ', + ) + .replaceAll( + RegExp(r' [\d]+:[\d]+ ', multiLine: true), + r' $LINE:$COL ', + ) + .replaceAll( + RegExp(r'Writing \d+ characters', multiLine: true), + r'Writing $N characters', + ); }
diff --git a/test/embedding/get_executable_for_command_test.dart b/test/embedding/get_executable_for_command_test.dart index e174f3a..0edfa72 100644 --- a/test/embedding/get_executable_for_command_test.dart +++ b/test/embedding/get_executable_for_command_test.dart
@@ -2,22 +2,31 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' show separator; import 'package:path/path.dart' as p; import 'package:pub/pub.dart'; +import 'package:pub/src/log.dart' as log; + import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -Future<void> testGetExecutable(String command, String root, - {allowSnapshot = true, result, errorMessage}) async { +Future<void> testGetExecutable( + String command, + String root, { + allowSnapshot = true, + executable, + packageConfig, + errorMessage, + CommandResolutionIssue? issue, +}) async { final _cachePath = getPubTestEnvironment()['PUB_CACHE']; - if (result == null) { + final oldVerbosity = log.verbosity; + log.verbosity = log.Verbosity.none; + if (executable == null) { expect( () => getExecutableForCommand( command, @@ -27,18 +36,25 @@ ), throwsA( isA<CommandResolutionFailedException>() - .having((e) => e.message, 'message', errorMessage), + .having((e) => e.message, 'message', errorMessage) + .having((e) => e.issue, 'issue', issue), ), ); } else { - final path = await getExecutableForCommand( + final e = await getExecutableForCommand( command, root: root, pubCacheDir: _cachePath, allowSnapshot: allowSnapshot, ); - expect(path, result); - expect(File(p.join(root, path)).existsSync(), true); + expect( + e, + isA<DartExecutableWithPackageConfig>() + .having((e) => e.executable, 'executable', executable) + .having((e) => e.packageConfig, 'packageConfig', packageConfig), + ); + expect(File(p.join(root, e.executable)).existsSync(), true); + log.verbosity = oldVerbosity; } } @@ -50,13 +66,13 @@ final dir = d.path('foo'); await testGetExecutable('bar/bar.dart', dir, - result: p.join('bar', 'bar.dart')); + executable: p.join('bar', 'bar.dart')); await testGetExecutable(p.join('bar', 'bar.dart'), dir, - result: p.join('bar', 'bar.dart')); + executable: p.join('bar', 'bar.dart')); await testGetExecutable('${p.toUri(dir)}/bar/bar.dart', dir, - result: p.join('bar', 'bar.dart')); + executable: p.join('bar', 'bar.dart')); }); test('Looks for file when no pubspec.yaml', () async { @@ -66,9 +82,11 @@ final dir = d.path('foo'); await testGetExecutable('bar/m.dart', dir, - errorMessage: contains('Could not find file `bar/m.dart`')); + errorMessage: contains('Could not find file `bar/m.dart`'), + issue: CommandResolutionIssue.fileNotFound); await testGetExecutable(p.join('bar', 'm.dart'), dir, - errorMessage: contains('Could not find file `bar${separator}m.dart`')); + errorMessage: contains('Could not find file `bar${separator}m.dart`'), + issue: CommandResolutionIssue.fileNotFound); }); test('Error message when pubspec is broken', () async { @@ -95,13 +113,15 @@ contains( 'Error on line 1, column 9 of ${d.sandbox}${p.separator}foo${p.separator}pubspec.yaml: "name" field must be a valid Dart identifier.'), contains( - '{"name":"broken name","environment":{"sdk":">=0.1.2 <1.0.0"}}'))); + '{"name":"broken name","environment":{"sdk":">=0.1.2 <1.0.0"}}')), + issue: CommandResolutionIssue.pubGetFailed); }); test('Does `pub get` if there is a pubspec.yaml', () async { await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', + 'environment': {'sdk': '>=$_currentVersion <3.0.0'}, 'dependencies': {'foo': '^1.0.0'} }), d.dir('bin', [ @@ -109,23 +129,64 @@ ]) ]).create(); - await serveNoPackages(); + await servePackages(); // The solver uses word-wrapping in its error message, so we use \s to // accomodate. - await testGetExecutable('bar/m.dart', d.path(appPath), - errorMessage: matches(r'version\s+solving\s+failed')); + await testGetExecutable( + 'bar/m.dart', + d.path(appPath), + errorMessage: matches(r'version\s+solving\s+failed'), + issue: CommandResolutionIssue.pubGetFailed, + ); + }); + + test('Reports parse failure', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=$_currentVersion <3.0.0'}, + }), + ]).create(); + await testGetExecutable( + '::', + d.path(appPath), + errorMessage: contains(r'cannot contain multiple ":"'), + issue: CommandResolutionIssue.parseError, + ); + }); + + test('Reports compilation failure', () async { + await d.dir(appPath, [ + d.pubspec({ + 'name': 'myapp', + 'environment': {'sdk': '>=$_currentVersion <3.0.0'}, + }), + d.dir('bin', [ + d.file('foo.dart', 'main() {'), + ]) + ]).create(); + + await servePackages(); + // The solver uses word-wrapping in its error message, so we use \s to + // accomodate. + await testGetExecutable( + ':foo', + d.path(appPath), + errorMessage: matches(r'foo.dart:1:8:'), + issue: CommandResolutionIssue.compilationFailed, + ); }); test('Finds files', () async { - await servePackages((b) => b - ..serve('foo', '1.0.0', pubspec: { - 'environment': {'sdk': '>=$_currentVersion <3.0.0'} - }, contents: [ - d.dir('bin', [ - d.file('foo.dart', 'main() {print(42);}'), - d.file('tool.dart', 'main() {print(42);}') - ]) - ])); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'environment': {'sdk': '>=$_currentVersion <3.0.0'} + }, contents: [ + d.dir('bin', [ + d.file('foo.dart', 'main() {print(42);}'), + d.file('tool.dart', 'main() {print(42);}') + ]) + ]); await d.dir(appPath, [ d.pubspec({ @@ -148,46 +209,81 @@ ]).create(); final dir = d.path(appPath); - await testGetExecutable('myapp', dir, - result: p.join('.dart_tool', 'pub', 'bin', 'myapp', - 'myapp.dart-$_currentVersion.snapshot')); - await testGetExecutable('myapp:myapp', dir, - result: p.join('.dart_tool', 'pub', 'bin', 'myapp', - 'myapp.dart-$_currentVersion.snapshot')); - await testGetExecutable(':myapp', dir, - result: p.join('.dart_tool', 'pub', 'bin', 'myapp', - 'myapp.dart-$_currentVersion.snapshot')); - await testGetExecutable(':tool', dir, - result: p.join('.dart_tool', 'pub', 'bin', 'myapp', - 'tool.dart-$_currentVersion.snapshot')); - await testGetExecutable('foo', dir, - allowSnapshot: false, - result: endsWith('foo-1.0.0${separator}bin${separator}foo.dart')); - await testGetExecutable('foo', dir, - result: - '.dart_tool${separator}pub${separator}bin${separator}foo${separator}foo.dart-$_currentVersion.snapshot'); - await testGetExecutable('foo:tool', dir, - allowSnapshot: false, - result: endsWith('foo-1.0.0${separator}bin${separator}tool.dart')); - await testGetExecutable('foo:tool', dir, - result: - '.dart_tool${separator}pub${separator}bin${separator}foo${separator}tool.dart-$_currentVersion.snapshot'); + await testGetExecutable( + 'myapp', + dir, + executable: p.join('.dart_tool', 'pub', 'bin', 'myapp', + 'myapp.dart-$_currentVersion.snapshot'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + 'myapp:myapp', + dir, + executable: p.join('.dart_tool', 'pub', 'bin', 'myapp', + 'myapp.dart-$_currentVersion.snapshot'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + ':myapp', + dir, + executable: p.join('.dart_tool', 'pub', 'bin', 'myapp', + 'myapp.dart-$_currentVersion.snapshot'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + ':tool', + dir, + executable: p.join('.dart_tool', 'pub', 'bin', 'myapp', + 'tool.dart-$_currentVersion.snapshot'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + 'foo', + dir, + allowSnapshot: false, + executable: endsWith('foo-1.0.0${separator}bin${separator}foo.dart'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + 'foo', + dir, + executable: + '.dart_tool${separator}pub${separator}bin${separator}foo${separator}foo.dart-$_currentVersion.snapshot', + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + 'foo:tool', + dir, + allowSnapshot: false, + executable: endsWith('foo-1.0.0${separator}bin${separator}tool.dart'), + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); + await testGetExecutable( + 'foo:tool', + dir, + executable: + '.dart_tool${separator}pub${separator}bin${separator}foo${separator}tool.dart-$_currentVersion.snapshot', + packageConfig: p.join('.dart_tool', 'package_config.json'), + ); await testGetExecutable( 'unknown:tool', dir, errorMessage: 'Could not find package `unknown` or file `unknown:tool`', + issue: CommandResolutionIssue.packageNotFound, ); await testGetExecutable( 'foo:unknown', dir, errorMessage: 'Could not find `bin${separator}unknown.dart` in package `foo`.', + issue: CommandResolutionIssue.noBinaryFound, ); await testGetExecutable( 'unknownTool', dir, errorMessage: 'Could not find package `unknownTool` or file `unknownTool`', + issue: CommandResolutionIssue.packageNotFound, ); }); }
diff --git a/test/embedding/goldens/helptext.txt b/test/embedding/goldens/helptext.txt deleted file mode 100644 index b5c206f..0000000 --- a/test/embedding/goldens/helptext.txt +++ /dev/null
@@ -1,113 +0,0 @@ -$ tool/test-bin/pub_command_runner.dart -[E] Could not find a command named "". -[E] -[E] Usage: pub_command_runner <command> [arguments] -[E] -[E] Global options: -[E] -h, --help Print this usage information. -[E] -[E] Available commands: -[E] pub Work with packages. -[E] -[E] Run "pub_command_runner help <command>" for more information about a command. - -$ tool/test-bin/pub_command_runner.dart --help -Tests the embeddable pub command. - -Usage: pub_command_runner <command> [arguments] - -Global options: --h, --help Print this usage information. - -Available commands: - pub Work with packages. - -Run "pub_command_runner help <command>" for more information about a command. - -$ tool/test-bin/pub_command_runner.dart pub -[E] Missing subcommand for "pub_command_runner pub". -[E] -[E] Usage: pub_command_runner pub [arguments...] -[E] -h, --help Print this usage information. -[E] --[no-]trace Print debugging information when an error occurs. -[E] -v, --verbose Shortcut for "--verbosity=all". -[E] -C, --directory=<dir> Run the subcommand in the directory<dir>. -[E] (defaults to ".") -[E] -[E] Available subcommands: -[E] add Add a dependency to pubspec.yaml. -[E] cache Work with the system cache. -[E] deps Print package dependencies. -[E] downgrade Downgrade the current package's dependencies to oldest versions. -[E] get Get the current package's dependencies. -[E] global Work with global packages. -[E] login Log into pub.dev. -[E] logout Log out of pub.dev. -[E] outdated Analyze your dependencies to find which ones can be upgraded. -[E] publish Publish the current package to pub.dartlang.org. -[E] remove Removes a dependency from the current package. -[E] token Manage authentication tokens for hosted pub repositories. -[E] upgrade Upgrade the current package's dependencies to latest versions. -[E] uploader Manage uploaders for a package on pub.dartlang.org. -[E] -[E] Run "pub_command_runner help" to see global options. -[E] See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. - -$ tool/test-bin/pub_command_runner.dart pub --help -Work with packages. - -Usage: pub_command_runner pub [arguments...] --h, --help Print this usage information. - --[no-]trace Print debugging information when an error occurs. --v, --verbose Shortcut for "--verbosity=all". --C, --directory=<dir> Run the subcommand in the directory<dir>. - (defaults to ".") - -Available subcommands: - add Add a dependency to pubspec.yaml. - cache Work with the system cache. - deps Print package dependencies. - downgrade Downgrade the current package's dependencies to oldest versions. - get Get the current package's dependencies. - global Work with global packages. - login Log into pub.dev. - logout Log out of pub.dev. - outdated Analyze your dependencies to find which ones can be upgraded. - publish Publish the current package to pub.dartlang.org. - remove Removes a dependency from the current package. - token Manage authentication tokens for hosted pub repositories. - upgrade Upgrade the current package's dependencies to latest versions. - uploader Manage uploaders for a package on pub.dartlang.org. - -Run "pub_command_runner help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. - -$ tool/test-bin/pub_command_runner.dart pub get --help -Get the current package's dependencies. - -Usage: pub_command_runner pub get <subcommand> [arguments...] --h, --help Print this usage information. - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - --[no-]precompile Build executables in immediate dependencies. --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub_command_runner help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation. - -$ tool/test-bin/pub_command_runner.dart pub global -[E] Missing subcommand for "pub_command_runner pub global". -[E] -[E] Usage: pub_command_runner pub global [arguments...] -[E] -h, --help Print this usage information. -[E] -[E] Available subcommands: -[E] activate Make a package's executables globally available. -[E] deactivate Remove a previously activated package. -[E] list List globally activated packages. -[E] run Run an executable from a globally activated package. -[E] -[E] Run "pub_command_runner help" to see global options. -[E] See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. -
diff --git a/test/embedding/goldens/run.txt b/test/embedding/goldens/run.txt deleted file mode 100644 index 6f0f46a..0000000 --- a/test/embedding/goldens/run.txt +++ /dev/null
@@ -1,7 +0,0 @@ -$ tool/test-bin/pub_command_runner.dart pub get -Resolving dependencies... -Got dependencies! - -$ tool/test-bin/pub_command_runner.dart pub run bin/main.dart -Hi -
diff --git a/test/get/dry_run_does_not_apply_changes_test.dart b/test/get/dry_run_does_not_apply_changes_test.dart index 1879f51..3e44bf9 100644 --- a/test/get/dry_run_does_not_apply_changes_test.dart +++ b/test/get/dry_run_does_not_apply_changes_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -11,9 +9,8 @@ void main() { test('--dry-run shows but does not apply changes', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create();
diff --git a/test/get/flutter_constraint_upper_bound_ignored_test.dart b/test/get/flutter_constraint_upper_bound_ignored_test.dart index 9fc833c..7fd2edc 100644 --- a/test/get/flutter_constraint_upper_bound_ignored_test.dart +++ b/test/get/flutter_constraint_upper_bound_ignored_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/gets_in_example_folder_test.dart b/test/get/gets_in_example_folder_test.dart index d7f6c57..04f9d47 100644 --- a/test/get/gets_in_example_folder_test.dart +++ b/test/get/gets_in_example_folder_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart = 2.11 - import 'dart:io'; import 'package:path/path.dart' as p;
diff --git a/test/get/git/check_out_and_upgrade_test.dart b/test/get/git/check_out_and_upgrade_test.dart index 846859b..42044af 100644 --- a/test/get/git/check_out_and_upgrade_test.dart +++ b/test/get/git/check_out_and_upgrade_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/check_out_branch_test.dart b/test/get/git/check_out_branch_test.dart index 0b58abf..104c8b9 100644 --- a/test/get/git/check_out_branch_test.dart +++ b/test/get/git/check_out_branch_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/check_out_revision_test.dart b/test/get/git/check_out_revision_test.dart index eed9f01..2428d7c 100644 --- a/test/get/git/check_out_revision_test.dart +++ b/test/get/git/check_out_revision_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/check_out_test.dart b/test/get/git/check_out_test.dart index 194e980..f3caaa2 100644 --- a/test/get/git/check_out_test.dart +++ b/test/get/git/check_out_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p;
diff --git a/test/get/git/check_out_transitive_test.dart b/test/get/git/check_out_transitive_test.dart index b7e71fa..0587c58 100644 --- a/test/get/git/check_out_transitive_test.dart +++ b/test/get/git/check_out_transitive_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/git/check_out_twice_test.dart b/test/get/git/check_out_twice_test.dart index f9cebd1..b6de388 100644 --- a/test/get/git/check_out_twice_test.dart +++ b/test/get/git/check_out_twice_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart b/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart index c5fc4aa..dae234d 100644 --- a/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart +++ b/test/get/git/check_out_unfetched_revision_of_cached_repo_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart';
diff --git a/test/get/git/check_out_with_trailing_slash_test.dart b/test/get/git/check_out_with_trailing_slash_test.dart index 16dc07c..5838986 100644 --- a/test/get/git/check_out_with_trailing_slash_test.dart +++ b/test/get/git/check_out_with_trailing_slash_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/clean_invalid_git_repo_cache_test.dart b/test/get/git/clean_invalid_git_repo_cache_test.dart index 6ea650b..ab386ab 100644 --- a/test/get/git/clean_invalid_git_repo_cache_test.dart +++ b/test/get/git/clean_invalid_git_repo_cache_test.dart
@@ -2,7 +2,6 @@ // 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. -// @dart=2.10 import 'dart:io'; import 'package:path/path.dart' as path; @@ -15,11 +14,10 @@ void _invalidateGitCache(String repo) { final cacheDir = path.join(d.sandbox, path.joinAll([cachePath, 'git', 'cache'])); - final Directory fooCacheDir = - Directory(cacheDir).listSync().firstWhere((entity) { + final fooCacheDir = Directory(cacheDir).listSync().firstWhere((entity) { return entity is Directory && entity.path.split(Platform.pathSeparator).last.startsWith(repo); - }); + }) as Directory; fooCacheDir.deleteSync(recursive: true); fooCacheDir.createSync();
diff --git a/test/get/git/dependency_name_match_pubspec_test.dart b/test/get/git/dependency_name_match_pubspec_test.dart index 2accd62..1545fca 100644 --- a/test/get/git/dependency_name_match_pubspec_test.dart +++ b/test/get/git/dependency_name_match_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/git/different_repo_name_test.dart b/test/get/git/different_repo_name_test.dart index 65e37eb..1d8f9c4 100644 --- a/test/get/git/different_repo_name_test.dart +++ b/test/get/git/different_repo_name_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/doesnt_fetch_if_nothing_changes_test.dart b/test/get/git/doesnt_fetch_if_nothing_changes_test.dart index ec214d4..3d9f040 100644 --- a/test/get/git/doesnt_fetch_if_nothing_changes_test.dart +++ b/test/get/git/doesnt_fetch_if_nothing_changes_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart';
diff --git a/test/get/git/git_not_installed_test.dart b/test/get/git/git_not_installed_test.dart index 13a5601..f00d795 100644 --- a/test/get/git/git_not_installed_test.dart +++ b/test/get/git/git_not_installed_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - @TestOn('linux') import 'dart:io';
diff --git a/test/get/git/lock_version_test.dart b/test/get/git/lock_version_test.dart index 1e51d12..40b2708 100644 --- a/test/get/git/lock_version_test.dart +++ b/test/get/git/lock_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart';
diff --git a/test/get/git/locked_revision_without_repo_test.dart b/test/get/git/locked_revision_without_repo_test.dart index 49c1a11..c00c730 100644 --- a/test/get/git/locked_revision_without_repo_test.dart +++ b/test/get/git/locked_revision_without_repo_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart';
diff --git a/test/get/git/path_test.dart b/test/get/git/path_test.dart index 8bbd9e7..a323be7 100644 --- a/test/get/git/path_test.dart +++ b/test/get/git/path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:pub/src/lock_file.dart'; @@ -39,9 +37,11 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub', + path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir')), + ]).validate(); }); test('depends on a package in a deep subdirectory', () async { @@ -73,14 +73,17 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub', + path: + pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')), + ]).validate(); final lockFile = LockFile.load( p.join(d.sandbox, appPath, 'pubspec.lock'), SourceRegistry()); - expect(lockFile.packages['sub'].description['path'], 'sub/dir%25', + expect(lockFile.packages['sub']!.description['path'], 'sub/dir%25', reason: 'use uris to specify the path relative to the repo'); }); @@ -117,14 +120,17 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub': pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub', + path: + pathInCache('git/foo-${await repo.revParse('HEAD')}/sub/dir%25')), + ]).validate(); final lockFile = LockFile.load( p.join(d.sandbox, appPath, 'pubspec.lock'), SourceRegistry()); - expect(lockFile.packages['sub'].description['path'], 'sub/dir%25', + expect(lockFile.packages['sub']!.description['path'], 'sub/dir%25', reason: 'use uris to specify the path relative to the repo'); }); @@ -160,10 +166,14 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub1': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir1'), - 'sub2': pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir2') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub1', + path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir1')), + d.packageConfigEntry( + name: 'sub2', + path: pathInCache('git/foo-${await repo.revParse('HEAD')}/subdir2')), + ]).validate(); }); test('depends on packages in the same subdirectory at different revisions', @@ -208,9 +218,11 @@ ]) ]).validate(); - await d.appPackagesFile({ - 'sub1': pathInCache('git/foo-$oldRevision/subdir'), - 'sub2': pathInCache('git/foo-$newRevision/subdir') - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'sub1', path: pathInCache('git/foo-$oldRevision/subdir')), + d.packageConfigEntry( + name: 'sub2', path: pathInCache('git/foo-$newRevision/subdir')), + ]).validate(); }); }
diff --git a/test/get/git/require_pubspec_name_test.dart b/test/get/git/require_pubspec_name_test.dart index e0815b2..adc31e4 100644 --- a/test/get/git/require_pubspec_name_test.dart +++ b/test/get/git/require_pubspec_name_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/git/require_pubspec_test.dart b/test/get/git/require_pubspec_test.dart index fb1dd56..0f75c75 100644 --- a/test/get/git/require_pubspec_test.dart +++ b/test/get/git/require_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/stay_locked_if_compatible_test.dart b/test/get/git/stay_locked_if_compatible_test.dart index 615a11b..d7f6eb9 100644 --- a/test/get/git/stay_locked_if_compatible_test.dart +++ b/test/get/git/stay_locked_if_compatible_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/git/unlock_if_incompatible_test.dart b/test/get/git/unlock_if_incompatible_test.dart index 1a97136..61b60e6 100644 --- a/test/get/git/unlock_if_incompatible_test.dart +++ b/test/get/git/unlock_if_incompatible_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/get/hosted/avoid_network_requests_test.dart b/test/get/hosted/avoid_network_requests_test.dart index 4a0cd90..c62fa7c 100644 --- a/test/get/hosted/avoid_network_requests_test.dart +++ b/test/get/hosted/avoid_network_requests_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,14 +9,13 @@ void main() { test('only requests versions that are needed during solving', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.0'); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.1.0'); - builder.serve('bar', '1.2.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.1.0') + ..serve('foo', '1.2.0') + ..serve('bar', '1.0.0') + ..serve('bar', '1.1.0') + ..serve('bar', '1.2.0'); await d.appDir({'foo': 'any'}).create(); @@ -34,8 +31,10 @@ // Run the solver again. await pubGet(); - - await d.appPackagesFile({'foo': '1.2.0', 'bar': '1.2.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.0'), + d.packageConfigEntry(name: 'bar', version: '1.2.0'), + ]).validate(); // The get should not have done any network requests since the lock file is // up to date.
diff --git a/test/get/hosted/cached_pubspec_test.dart b/test/get/hosted/cached_pubspec_test.dart index c4711c8..fa9decc 100644 --- a/test/get/hosted/cached_pubspec_test.dart +++ b/test/get/hosted/cached_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,7 +9,8 @@ void main() { test('does not request a pubspec for a cached package', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({'foo': '1.2.3'}).create(); @@ -20,16 +19,18 @@ // Clear the cache. We don't care about anything that was served during // the initial get. - globalServer.requestedPaths.clear(); + server.requestedPaths.clear(); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); // Run the solver again now that it's cached. await pubGet(); // The get should not have requested the pubspec since it's local already. - expect(globalServer.requestedPaths, + expect(server.requestedPaths, isNot(contains('packages/foo/versions/1.2.3.yaml'))); }); }
diff --git a/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart b/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart index c635399..44fe075 100644 --- a/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart +++ b/test/get/hosted/do_not_upgrade_on_removed_constraints_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,24 +11,29 @@ test( "doesn't upgrade dependencies whose constraints have been " 'removed', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'}); - builder.serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'}); - builder.serve('shared_dep', '1.0.0'); - builder.serve('shared_dep', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'}) + ..serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'}) + ..serve('shared_dep', '1.0.0') + ..serve('shared_dep', '2.0.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubGet(); - await d.appPackagesFile( - {'foo': '1.0.0', 'bar': '1.0.0', 'shared_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'), + ]).validate(); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0', 'shared_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/does_no_network_requests_when_possible_test.dart b/test/get/hosted/does_no_network_requests_when_possible_test.dart index bca2c4d..4324776 100644 --- a/test/get/hosted/does_no_network_requests_when_possible_test.dart +++ b/test/get/hosted/does_no_network_requests_when_possible_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('does not request versions if the lockfile is up to date', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.0'); - }); + final server = await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.1.0') + ..serve('foo', '1.2.0'); await d.appDir({'foo': 'any'}).create(); @@ -24,16 +21,18 @@ // Clear the cache. We don't care about anything that was served during // the initial get. - globalServer.requestedPaths.clear(); + server.requestedPaths.clear(); // Run the solver again now that it's cached. await pubGet(); await d.cacheDir({'foo': '1.2.0'}).validate(); - await d.appPackagesFile({'foo': '1.2.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.0'), + ]).validate(); // The get should not have done any network requests since the lock file is // up to date. - expect(globalServer.requestedPaths, isEmpty); + expect(server.requestedPaths, isEmpty); }); }
diff --git a/test/get/hosted/explain_bad_hosted_url_test.dart b/test/get/hosted/explain_bad_hosted_url_test.dart index 6de6860..feebf67 100644 --- a/test/get/hosted/explain_bad_hosted_url_test.dart +++ b/test/get/hosted/explain_bad_hosted_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -34,11 +32,12 @@ }); test('Allows PUB_HOSTED_URL to end with a slash', () async { - await servePackages((b) => b.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet( - environment: {'PUB_HOSTED_URL': '${globalPackageServer.url}/'}, + environment: {'PUB_HOSTED_URL': '${globalServer.url}/'}, ); }); }
diff --git a/test/get/hosted/get_stress_test.dart b/test/get/hosted/get_stress_test.dart index 8a05104..026c0c1 100644 --- a/test/get/hosted/get_stress_test.dart +++ b/test/get/hosted/get_stress_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,12 +9,11 @@ void main() { test('gets more than 16 packages from a pub server', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - for (var i = 0; i < 20; i++) { - builder.serve('pkg$i', '1.$i.0'); - } - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); + for (var i = 0; i < 20; i++) { + server.serve('pkg$i', '1.$i.0'); + } await d.appDir({ 'foo': '1.2.3', @@ -29,10 +26,10 @@ 'foo': '1.2.3', for (var i = 0; i < 20; i++) 'pkg$i': '1.$i.0', }).validate(); - - await d.appPackagesFile({ - 'foo': '1.2.3', - for (var i = 0; i < 20; i++) 'pkg$i': '1.$i.0', - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + for (var i = 0; i < 20; i++) + d.packageConfigEntry(name: 'pkg$i', version: '1.$i.0') + ]).validate(); }); }
diff --git a/test/get/hosted/get_test.dart b/test/get/hosted/get_test.dart index 13f9ad8..f0270a3 100644 --- a/test/get/hosted/get_test.dart +++ b/test/get/hosted/get_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart'; @@ -15,18 +13,21 @@ void main() { test('gets a package from a pub server', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); }); test('URL encodes the package name', () async { - await serveNoPackages(); + await servePackages(); await d.appDir({'bad name!': '1.2.3'}).create(); @@ -43,11 +44,10 @@ test('gets a package from a non-default pub server', () async { // Make the default server serve errors. Only the custom server should // be accessed. - await serveErrors(); + (await servePackages()).serveErrors(); - var server = await PackageServer.start((builder) { - builder.serve('foo', '1.2.3'); - }); + var server = await startPackageServer(); + server.serve('foo', '1.2.3'); await d.appDir({ 'foo': { @@ -59,18 +59,21 @@ await pubGet(); await d.cacheDir({'foo': '1.2.3'}, port: server.port).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3', server: server), + ]).validate(); }); group('categorizes dependency types in the lockfile', () { - setUp(() => servePackages((builder) { - builder.serve('foo', '1.2.3', deps: {'bar': 'any'}); - builder.serve('bar', '1.2.3'); - builder.serve('baz', '1.2.3', deps: {'qux': 'any'}); - builder.serve('qux', '1.2.3'); - builder.serve('zip', '1.2.3', deps: {'zap': 'any'}); - builder.serve('zap', '1.2.3'); - })); + setUp(() async { + await servePackages() + ..serve('foo', '1.2.3', deps: {'bar': 'any'}) + ..serve('bar', '1.2.3') + ..serve('baz', '1.2.3', deps: {'qux': 'any'}) + ..serve('qux', '1.2.3') + ..serve('zip', '1.2.3', deps: {'zap': 'any'}) + ..serve('zap', '1.2.3'); + }); test('for main, dev, and overridden dependencies', () async { await d.dir(appPath, [
diff --git a/test/get/hosted/get_transitive_test.dart b/test/get/hosted/get_transitive_test.dart index 4640c44..0ae18ac 100644 --- a/test/get/hosted/get_transitive_test.dart +++ b/test/get/hosted/get_transitive_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,18 +9,20 @@ void main() { test('gets packages transitively from a pub server', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', deps: {'bar': '2.0.4'}); - builder.serve('bar', '2.0.3'); - builder.serve('bar', '2.0.4'); - builder.serve('bar', '2.0.5'); - }); + await servePackages() + ..serve('foo', '1.2.3', deps: {'bar': '2.0.4'}) + ..serve('bar', '2.0.3') + ..serve('bar', '2.0.4') + ..serve('bar', '2.0.5'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); await d.cacheDir({'foo': '1.2.3', 'bar': '2.0.4'}).validate(); - await d.appPackagesFile({'foo': '1.2.3', 'bar': '2.0.4'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + d.packageConfigEntry(name: 'bar', version: '2.0.4'), + ]).validate(); }); }
diff --git a/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart b/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart index 14f1d98..585cfba 100644 --- a/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart +++ b/test/get/hosted/gets_a_package_with_busted_dev_dependencies_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -14,12 +12,11 @@ test( 'gets a dependency with broken dev dependencies from a pub ' 'server', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', pubspec: { - 'dev_dependencies': { - 'busted': {'not a real source': null} - } - }); + final server = await servePackages(); + server.serve('foo', '1.2.3', pubspec: { + 'dev_dependencies': { + 'busted': {'not a real source': null} + } }); await d.appDir({'foo': '1.2.3'}).create(); @@ -27,6 +24,8 @@ await pubGet(); await d.cacheDir({'foo': '1.2.3'}).validate(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); }); }
diff --git a/test/get/hosted/resolve_constraints_test.dart b/test/get/hosted/resolve_constraints_test.dart index cf3d434..466902e 100644 --- a/test/get/hosted/resolve_constraints_test.dart +++ b/test/get/hosted/resolve_constraints_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,13 +9,12 @@ void main() { test('resolves version constraints from a pub server', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', deps: {'baz': '>=2.0.0'}); - builder.serve('bar', '2.3.4', deps: {'baz': '<3.0.0'}); - builder.serve('baz', '2.0.3'); - builder.serve('baz', '2.0.4'); - builder.serve('baz', '3.0.1'); - }); + await servePackages() + ..serve('foo', '1.2.3', deps: {'baz': '>=2.0.0'}) + ..serve('bar', '2.3.4', deps: {'baz': '<3.0.0'}) + ..serve('baz', '2.0.3') + ..serve('baz', '2.0.4') + ..serve('baz', '3.0.1'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); @@ -25,8 +22,10 @@ await d .cacheDir({'foo': '1.2.3', 'bar': '2.3.4', 'baz': '2.0.4'}).validate(); - - await d.appPackagesFile( - {'foo': '1.2.3', 'bar': '2.3.4', 'baz': '2.0.4'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + d.packageConfigEntry(name: 'bar', version: '2.3.4'), + d.packageConfigEntry(name: 'baz', version: '2.0.4'), + ]).validate(); }); }
diff --git a/test/get/hosted/resolve_with_retracted_package_versions_test.dart b/test/get/hosted/resolve_with_retracted_package_versions_test.dart index af714cf..d9b33a4 100644 --- a/test/get/hosted/resolve_with_retracted_package_versions_test.dart +++ b/test/get/hosted/resolve_with_retracted_package_versions_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; @@ -15,28 +13,29 @@ void main() { test('Do not consider retracted packages', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'}) ..serve('bar', '1.0.0') - ..serve('bar', '1.1.0')); + ..serve('bar', '1.1.0'); await d.appDir({'foo': '1.0.0'}).create(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.1.0')); + server.retractPackageVersion('bar', '1.1.0'); await pubGet(); await d.cacheDir({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('Error when the only available package version is retracted', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'}) - ..serve('bar', '1.0.0')); + ..serve('bar', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.0.0')); + server.retractPackageVersion('bar', '1.0.0'); await pubGet( error: '''Because every version of foo depends on bar ^1.0.0 which doesn't match any versions, foo is forbidden. @@ -49,39 +48,51 @@ // In this case we expect a newer version to be published at some point which // will then cause pub upgrade to choose that one. test('Allow retracted version when it was already in pubspec.lock', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'}) ..serve('bar', '1.0.0') - ..serve('bar', '1.1.0')); + ..serve('bar', '1.1.0'); await d.appDir({'foo': '1.0.0'}).create(); await pubGet(); await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + ]).validate(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.1.0')); + server.retractPackageVersion('bar', '1.1.0'); await pubUpgrade(); await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + ]).validate(); - globalPackageServer.add((builder) => builder..serve('bar', '2.0.0')); + server.serve('bar', '2.0.0'); await pubUpgrade(); await d.cacheDir({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + ]).validate(); - globalPackageServer.add((builder) => builder..serve('bar', '1.2.0')); + server.serve('bar', '1.2.0'); await pubUpgrade(); await d.cacheDir({'foo': '1.0.0', 'bar': '1.2.0'}).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.2.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.2.0'), + ]).validate(); }); test('Offline versions of pub commands also handle retracted packages', () async { + final server = await servePackages(); await populateCache({ 'foo': ['1.0.0'], 'bar': ['1.0.0', '1.1.0'] - }); + }, server); await d.cacheDir({ 'foo': '1.0.0', @@ -89,25 +100,27 @@ }).validate(); final barVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'bar-versions.json'); + p.join(globalServer.cachingPath, '.cache', 'bar-versions.json'); expect(fileExists(barVersionsCache), isTrue); deleteEntry(barVersionsCache); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.1.0')); + server.retractPackageVersion('bar', '1.1.0'); await pubGet(); await d.cacheDir({'bar': '1.1.0'}).validate(); // Now serve only errors - to validate we are truly offline. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': '1.0.0', 'bar': '^1.0.0'}).create(); await pubUpgrade(args: ['--offline']); // We choose bar 1.1.0 since we already have it in pubspec.lock - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + ]).validate(); // Delete lockfile so that retracted versions are not considered. final lockFile = p.join(d.sandbox, appPath, 'pubspec.lock'); @@ -115,15 +128,17 @@ deleteEntry(lockFile); await pubGet(args: ['--offline']); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('Allow retracted version when pinned in dependency_overrides', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - }); + final server = await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -133,31 +148,31 @@ }) ]).create(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('foo', '2.0.0')); + server.retractPackageVersion('foo', '2.0.0'); await pubGet(); - await d.appPackagesFile({'foo': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + ]).validate(); }); test('Prefer retracted version in dependency_overrides over pubspec.lock', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - }); + final server = await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('foo', '2.0.0')); - globalPackageServer - .add((builder) => builder..retractPackageVersion('foo', '3.0.0')); + server.retractPackageVersion('foo', '2.0.0'); + server.retractPackageVersion('foo', '3.0.0'); await pubUpgrade(); - await d.appPackagesFile({'foo': '3.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '3.0.0'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -168,6 +183,8 @@ ]).create(); await pubUpgrade(); - await d.appPackagesFile({'foo': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/stay_locked_if_compatible_test.dart b/test/get/hosted/stay_locked_if_compatible_test.dart index 588f395..df04579 100644 --- a/test/get/hosted/stay_locked_if_compatible_test.dart +++ b/test/get/hosted/stay_locked_if_compatible_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,20 +11,24 @@ test( "doesn't upgrade a locked pub server package with a new " 'compatible constraint', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); - - globalPackageServer.add((builder) => builder.serve('foo', '1.0.1')); + server.serve('foo', '1.0.1'); await d.appDir({'foo': '>=1.0.0'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart b/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart index 743c5f4..c75c435 100644 --- a/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart +++ b/test/get/hosted/stay_locked_if_new_is_satisfied_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,35 +11,34 @@ test( "doesn't unlock dependencies if a new dependency is already " 'satisfied', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); - builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}); - builder.serve('baz', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); + server.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}); + server.serve('baz', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'baz', version: '1.0.0'), + ]).validate(); - await d.appPackagesFile( - {'foo': '1.0.0', 'bar': '1.0.0', 'baz': '1.0.0'}).validate(); - - globalPackageServer.add((builder) { - builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); - builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}); - builder.serve('baz', '2.0.0'); - builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.0.0'}); - }); + server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); + server.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}); + server.serve('baz', '2.0.0'); + server.serve('newdep', '2.0.0', deps: {'baz': '>=1.0.0'}); await d.appDir({'foo': 'any', 'newdep': 'any'}).create(); await pubGet(); - await d.appPackagesFile({ - 'foo': '1.0.0', - 'bar': '1.0.0', - 'baz': '1.0.0', - 'newdep': '2.0.0' - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'baz', version: '1.0.0'), + d.packageConfigEntry(name: 'newdep', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/stay_locked_test.dart b/test/get/hosted/stay_locked_test.dart index c5c11ff..8b819ea 100644 --- a/test/get/hosted/stay_locked_test.dart +++ b/test/get/hosted/stay_locked_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -15,24 +13,28 @@ test( 'keeps a hosted package locked to the version in the ' 'lockfile', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': 'any'}).create(); // This should lock the foo dependency to version 1.0.0. await pubGet(); - - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); // Delete the .dart_tool/package_config.json file to simulate a new checkout of the application. deleteEntry(path.join(d.sandbox, packageConfigFilePath)); // Start serving a newer package as well. - globalPackageServer.add((builder) => builder.serve('foo', '1.0.1')); + server.serve('foo', '1.0.1'); // This shouldn't upgrade the foo dependency due to the lockfile. await pubGet(); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/unlock_if_incompatible_test.dart b/test/get/hosted/unlock_if_incompatible_test.dart index f9f8748..007231e 100644 --- a/test/get/hosted/unlock_if_incompatible_test.dart +++ b/test/get/hosted/unlock_if_incompatible_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,18 +11,23 @@ test( 'upgrades a locked pub server package with a new incompatible ' 'constraint', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); - globalPackageServer.add((builder) => builder.serve('foo', '1.0.1')); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); + server.serve('foo', '1.0.1'); await d.appDir({'foo': '>1.0.0'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.1'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.1'), + ]).validate(); }); }
diff --git a/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart b/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart index feaf478..ae6a4e6 100644 --- a/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart +++ b/test/get/hosted/unlock_if_new_is_unsatisfied_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,42 +11,40 @@ test( 'unlocks dependencies if necessary to ensure that a new ' 'dependency is satisfied', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); - builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}); - builder.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'}); - builder.serve('qux', '1.0.0'); - }); + final server = await servePackages(); + + server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); + server.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}); + server.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'}); + server.serve('qux', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({ - 'foo': '1.0.0', - 'bar': '1.0.0', - 'baz': '1.0.0', - 'qux': '1.0.0' - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'baz', version: '1.0.0'), + d.packageConfigEntry(name: 'qux', version: '1.0.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); - builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}); - builder.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'}); - builder.serve('qux', '2.0.0'); - builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'}); - }); + server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); + server.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}); + server.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'}); + server.serve('qux', '2.0.0'); + server.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'}); await d.appDir({'foo': 'any', 'newdep': 'any'}).create(); await pubGet(); - await d.appPackagesFile({ - 'foo': '2.0.0', - 'bar': '2.0.0', - 'baz': '2.0.0', - 'qux': '1.0.0', - 'newdep': '2.0.0' - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '2.0.0'), + d.packageConfigEntry(name: 'baz', version: '2.0.0'), + d.packageConfigEntry(name: 'qux', version: '1.0.0'), + d.packageConfigEntry(name: 'newdep', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/get/hosted/unlock_if_version_doesnt_exist_test.dart b/test/get/hosted/unlock_if_version_doesnt_exist_test.dart index f42e12e..e4cc01b 100644 --- a/test/get/hosted/unlock_if_version_doesnt_exist_test.dart +++ b/test/get/hosted/unlock_if_version_doesnt_exist_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -14,16 +12,23 @@ void main() { test('upgrades a locked pub server package with a nonexistent version', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); deleteEntry(p.join(d.sandbox, cachePath)); - globalPackageServer.replace((builder) => builder.serve('foo', '1.0.1')); + server.clearPackages(); + server.serve('foo', '1.0.1'); + await pubGet(); - await d.appPackagesFile({'foo': '1.0.1'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.1'), + ]).validate(); }); }
diff --git a/test/get/hosted/warn_about_discontinued_test.dart b/test/get/hosted/warn_about_discontinued_test.dart index 3913b2c..7057f9b 100644 --- a/test/get/hosted/warn_about_discontinued_test.dart +++ b/test/get/hosted/warn_about_discontinued_test.dart
@@ -2,36 +2,34 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; -import 'package:shelf/shelf.dart'; +import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; import '../../descriptor.dart' as d; import '../../test_pub.dart'; void main() { - test('Warns about discontinued packages', () async { - await servePackages((builder) => builder - ..serve('foo', '1.2.3', deps: {'transitive': 'any'}) - ..serve('transitive', '1.0.0')); + test('Warns about discontinued dependencies', () async { + final server = await servePackages(); + server.serve('foo', '1.2.3', deps: {'transitive': 'any'}); + server.serve('transitive', '1.0.0'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); - globalPackageServer.add((builder) => builder + server ..discontinue('foo') - ..discontinue('transitive')); + ..discontinue('transitive'); // A pub get straight away will not trigger the warning, as we cache // responses for a while. await pubGet(); final fooVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'foo-versions.json'); - final transitiveVersionsCache = p.join( - globalPackageServer.cachingPath, '.cache', 'transitive-versions.json'); + p.join(globalServer.cachingPath, '.cache', 'foo-versions.json'); + final transitiveVersionsCache = + p.join(globalServer.cachingPath, '.cache', 'transitive-versions.json'); expect(fileExists(fooVersionsCache), isTrue); expect(fileExists(transitiveVersionsCache), isTrue); deleteEntry(fooVersionsCache); @@ -40,7 +38,6 @@ await pubGet(output: ''' Resolving dependencies... foo 1.2.3 (discontinued) - transitive 1.0.0 (discontinued) Got dependencies! '''); expect(fileExists(fooVersionsCache), isTrue); @@ -49,12 +46,12 @@ c['_fetchedAt'] = DateTime.now().subtract(Duration(days: 5)).toIso8601String(); writeTextFile(fooVersionsCache, json.encode(c)); - globalPackageServer - .add((builder) => builder.discontinue('foo', replacementText: 'bar')); + + server.discontinue('foo', replacementText: 'bar'); + await pubGet(output: ''' Resolving dependencies... foo 1.2.3 (discontinued replaced by bar) - transitive 1.0.0 (discontinued) Got dependencies!'''); final c2 = json.decode(readTextFile(fooVersionsCache)); // Make a bad cached value to test that responses are actually from cache. @@ -62,22 +59,19 @@ writeTextFile(fooVersionsCache, json.encode(c2)); await pubGet(output: ''' Resolving dependencies... - transitive 1.0.0 (discontinued) Got dependencies!'''); // Repairing the cache should reset the package listing caches. await runPub(args: ['cache', 'repair']); await pubGet(output: ''' Resolving dependencies... foo 1.2.3 (discontinued replaced by bar) - transitive 1.0.0 (discontinued) Got dependencies!'''); // Test that --offline won't try to access the server for retrieving the // status. - await serveErrors(); + server.serveErrors(); await pubGet(args: ['--offline'], output: ''' Resolving dependencies... foo 1.2.3 (discontinued replaced by bar) - transitive 1.0.0 (discontinued) Got dependencies!'''); deleteEntry(fooVersionsCache); deleteEntry(transitiveVersionsCache); @@ -87,18 +81,91 @@ '''); }); + test('Warns about discontinued dev dependencies', () async { + final builder = await servePackages(); + builder + ..serve('foo', '1.2.3', deps: {'transitive': 'any'}) + ..serve('transitive', '1.0.0'); + + await d.dir(appPath, [ + d.file('pubspec.yaml', ''' +name: myapp +dependencies: + +dev_dependencies: + foo: 1.2.3 +environment: + sdk: '>=0.1.2 <1.0.0' +''') + ]).create(); + await pubGet(); + + builder + ..discontinue('foo') + ..discontinue('transitive'); + // A pub get straight away will not trigger the warning, as we cache + // responses for a while. + await pubGet(); + final fooVersionsCache = + p.join(globalServer.cachingPath, '.cache', 'foo-versions.json'); + expect(fileExists(fooVersionsCache), isTrue); + deleteEntry(fooVersionsCache); + // We warn only about the direct dependency here: + await pubGet(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued) +Got dependencies! +'''); + expect(fileExists(fooVersionsCache), isTrue); + final c = json.decode(readTextFile(fooVersionsCache)); + // Make the cache artificially old. + c['_fetchedAt'] = + DateTime.now().subtract(Duration(days: 5)).toIso8601String(); + writeTextFile(fooVersionsCache, json.encode(c)); + builder.discontinue('foo', replacementText: 'bar'); + await pubGet(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued replaced by bar) +Got dependencies!'''); + final c2 = json.decode(readTextFile(fooVersionsCache)); + // Make a bad cached value to test that responses are actually from cache. + c2['isDiscontinued'] = false; + writeTextFile(fooVersionsCache, json.encode(c2)); + await pubGet(output: ''' +Resolving dependencies... +Got dependencies!'''); + // Repairing the cache should reset the package listing caches. + await runPub(args: ['cache', 'repair']); + await pubGet(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued replaced by bar) +Got dependencies!'''); + // Test that --offline won't try to access the server for retrieving the + // status. + builder.serveErrors(); + await pubGet(args: ['--offline'], output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued replaced by bar) +Got dependencies!'''); + deleteEntry(fooVersionsCache); + await pubGet(args: ['--offline'], output: ''' +Resolving dependencies... +Got dependencies! +'''); + }); + test('get does not fail when status listing fails', () async { - await servePackages((builder) => builder..serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); final fooVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'foo-versions.json'); + p.join(globalServer.cachingPath, '.cache', 'foo-versions.json'); expect(fileExists(fooVersionsCache), isTrue); deleteEntry(fooVersionsCache); // Serve 400 on all requests. - globalPackageServer.extraHandlers - ..clear() - ..[RegExp('.*')] = (request) async => Response(400); + globalServer.handle(RegExp('.*'), + (shelf.Request request) => shelf.Response.notFound('Not found')); /// Even if we fail to get status we still report success if versions don't unlock. await pubGet();
diff --git a/test/get/hosted/warn_about_retracted_package_test.dart b/test/get/hosted/warn_about_retracted_package_test.dart index 5258d7c..2336c7f 100644 --- a/test/get/hosted/warn_about_retracted_package_test.dart +++ b/test/get/hosted/warn_about_retracted_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -13,38 +11,36 @@ void main() { test('Report retracted packages', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': 'any'}) - ..serve('bar', '1.0.0')); + ..serve('bar', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); await pubGet(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.0.0')); + server.retractPackageVersion('bar', '1.0.0'); // Delete the cache to trigger the report. final barVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'bar-versions.json'); + p.join(server.cachingPath, '.cache', 'bar-versions.json'); expect(fileExists(barVersionsCache), isTrue); deleteEntry(barVersionsCache); await pubGet(output: contains('bar 1.0.0 (retracted)')); }); test('Report retracted packages with newer version available', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'}) ..serve('bar', '1.0.0') ..serve('bar', '2.0.0') - ..serve('bar', '2.0.1-pre')); + ..serve('bar', '2.0.1-pre'); await d.appDir({'foo': '1.0.0'}).create(); await pubGet(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.0.0')); + server.retractPackageVersion('bar', '1.0.0'); // Delete the cache to trigger the report. final barVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'bar-versions.json'); + p.join(server.cachingPath, '.cache', 'bar-versions.json'); expect(fileExists(barVersionsCache), isTrue); deleteEntry(barVersionsCache); await pubGet(output: contains('bar 1.0.0 (retracted, 2.0.0 available)')); @@ -52,19 +48,18 @@ test('Report retracted packages with newer prerelease version available', () async { - await servePackages((builder) => builder + final server = await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0-pre'}) ..serve('bar', '1.0.0-pre') - ..serve('bar', '2.0.1-pre')); + ..serve('bar', '2.0.1-pre'); await d.appDir({'foo': '1.0.0'}).create(); await pubGet(); - globalPackageServer - .add((builder) => builder..retractPackageVersion('bar', '1.0.0-pre')); + server.retractPackageVersion('bar', '1.0.0-pre'); // Delete the cache to trigger the report. final barVersionsCache = - p.join(globalPackageServer.cachingPath, '.cache', 'bar-versions.json'); + p.join(server.cachingPath, '.cache', 'bar-versions.json'); expect(fileExists(barVersionsCache), isTrue); deleteEntry(barVersionsCache); await pubGet(
diff --git a/test/get/package_name_test.dart b/test/get/package_name_test.dart index f385cfe..b1328cc 100644 --- a/test/get/package_name_test.dart +++ b/test/get/package_name_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -58,7 +56,8 @@ await pubGet(); await d.dir(appPath, [ - d.packagesFile({'foo.bar.baz': '.'}), + d.packageConfigFile( + [d.packageConfigEntry(name: 'foo.bar.baz', path: '.')]) ]).validate(); }); }
diff --git a/test/get/path/absolute_path_test.dart b/test/get/path/absolute_path_test.dart index 7304f52..e1897e9 100644 --- a/test/get/path/absolute_path_test.dart +++ b/test/get/path/absolute_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -23,6 +21,8 @@ await pubGet(); - await d.appPackagesFile({'foo': path.join(d.sandbox, 'foo')}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: path.join(d.sandbox, 'foo')), + ]).validate(); }); }
diff --git a/test/get/path/absolute_symlink_test.dart b/test/get/path/absolute_symlink_test.dart index b0cd147..83d3433 100644 --- a/test/get/path/absolute_symlink_test.dart +++ b/test/get/path/absolute_symlink_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -26,8 +24,8 @@ await pubGet(); - await d.dir(appPath, [ - d.packagesFile({'myapp': '.', 'foo': fooPath}) + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: fooPath), ]).validate(); await d.dir('moved').create(); @@ -37,9 +35,9 @@ renameInSandbox(appPath, path.join('moved', appPath)); await d.dir('moved', [ - d.dir(appPath, [ - d.packagesFile({'myapp': '.', 'foo': fooPath}) - ]) + d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: fooPath), + ]), ]).validate(); }); }
diff --git a/test/get/path/empty_pubspec_test.dart b/test/get/path/empty_pubspec_test.dart index 5b94d70..0f9843f 100644 --- a/test/get/path/empty_pubspec_test.dart +++ b/test/get/path/empty_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/path/no_pubspec_test.dart b/test/get/path/no_pubspec_test.dart index d12477d..d328f25 100644 --- a/test/get/path/no_pubspec_test.dart +++ b/test/get/path/no_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/path/nonexistent_dir_test.dart b/test/get/path/nonexistent_dir_test.dart index 993590f..7616087 100644 --- a/test/get/path/nonexistent_dir_test.dart +++ b/test/get/path/nonexistent_dir_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/get/path/path_is_file_test.dart b/test/get/path/path_is_file_test.dart index 119a794..6fafd82 100644 --- a/test/get/path/path_is_file_test.dart +++ b/test/get/path/path_is_file_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart';
diff --git a/test/get/path/relative_path_test.dart b/test/get/path/relative_path_test.dart index a1d7437..e56a453 100644 --- a/test/get/path/relative_path_test.dart +++ b/test/get/path/relative_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/lock_file.dart'; import 'package:pub/src/source_registry.dart'; @@ -25,7 +23,9 @@ await pubGet(); - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); }); test('path is relative to containing pubspec', () async { @@ -47,8 +47,10 @@ await pubGet(); - await d.appPackagesFile( - {'foo': '../relative/foo', 'bar': '../relative/bar'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../relative/foo'), + d.packageConfigEntry(name: 'bar', path: '../relative/bar'), + ]).validate(); }); test('path is relative to containing pubspec when using --directory', @@ -74,9 +76,10 @@ workingDirectory: d.sandbox, output: contains('Changed 2 dependencies in myapp!')); - await d.appPackagesFile( - {'foo': '../relative/foo', 'bar': '../relative/bar'}, - ).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../relative/foo'), + d.packageConfigEntry(name: 'bar', path: '../relative/bar'), + ]).validate(); }); test('relative path preserved in the lockfile', () async { @@ -93,7 +96,7 @@ var lockfilePath = path.join(d.sandbox, appPath, 'pubspec.lock'); var lockfile = LockFile.load(lockfilePath, SourceRegistry()); - var description = lockfile.packages['foo'].description; + var description = lockfile.packages['foo']!.description; expect(description['relative'], isTrue); expect(description['path'], path.join(d.sandbox, 'foo'));
diff --git a/test/get/path/relative_symlink_test.dart b/test/get/path/relative_symlink_test.dart index e48ba41..9136a34 100644 --- a/test/get/path/relative_symlink_test.dart +++ b/test/get/path/relative_symlink_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - // Pub uses NTFS junction points to create links in the packages directory. // These (unlike the symlinks that are supported in Vista and later) do not // support relative paths. So this test, by design, will not pass on Windows. @@ -30,8 +28,8 @@ await pubGet(); - await d.dir(appPath, [ - d.packagesFile({'myapp': '.', 'foo': '../foo'}) + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), ]).validate(); await d.dir('moved').create(); @@ -43,8 +41,8 @@ renameInSandbox(appPath, path.join('moved', appPath)); await d.dir('moved', [ - d.dir(appPath, [ - d.packagesFile({'myapp': '.', 'foo': '../foo'}) + d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), ]) ]).validate(); });
diff --git a/test/get/path/shared_dependency_symlink_test.dart b/test/get/path/shared_dependency_symlink_test.dart index 7d1369c..d450838 100644 --- a/test/get/path/shared_dependency_symlink_test.dart +++ b/test/get/path/shared_dependency_symlink_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -42,13 +40,10 @@ await pubGet(); - await d.dir(appPath, [ - d.packagesFile({ - 'myapp': '.', - 'foo': '../foo', - 'bar': '../bar', - 'shared': '../shared' - }) + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + d.packageConfigEntry(name: 'bar', path: '../bar'), + d.packageConfigEntry(name: 'shared', path: '../shared'), ]).validate(); }); }
diff --git a/test/get/path/shared_dependency_test.dart b/test/get/path/shared_dependency_test.dart index 3525e6b..3ef91ae 100644 --- a/test/get/path/shared_dependency_test.dart +++ b/test/get/path/shared_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -37,8 +35,11 @@ await pubGet(); - await d.appPackagesFile( - {'foo': '../foo', 'bar': '../bar', 'shared': '../shared'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + d.packageConfigEntry(name: 'bar', path: '../bar'), + d.packageConfigEntry(name: 'shared', path: '../shared'), + ]).validate(); }); test('shared dependency with paths that normalize the same', () async { @@ -68,7 +69,10 @@ await pubGet(); - await d.appPackagesFile( - {'foo': '../foo', 'bar': '../bar', 'shared': '../shared'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + d.packageConfigEntry(name: 'bar', path: '../bar'), + d.packageConfigEntry(name: 'shared', path: '../shared'), + ]).validate(); }); }
diff --git a/test/get/preserve_lock_file_line_endings_test.dart b/test/get/preserve_lock_file_line_endings_test.dart index 8f6dc26..bfd015a 100644 --- a/test/get/preserve_lock_file_line_endings_test.dart +++ b/test/get/preserve_lock_file_line_endings_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/entrypoint.dart'; import 'package:test/test.dart';
diff --git a/test/get/sdk_constraint_required_test.dart b/test/get/sdk_constraint_required_test.dart index 3cb0f86..3f1e5c0 100644 --- a/test/get/sdk_constraint_required_test.dart +++ b/test/get/sdk_constraint_required_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -27,8 +25,8 @@ d.nothing('pubspec.lock'), // The "packages" directory should not have been generated. d.nothing('packages'), - // The ".packages" file should not have been created. - d.nothing('.packages'), + // The package config file should not have been created. + d.nothing('.dart_tool/package_config.json'), ]).validate(); }); }
diff --git a/test/get/switch_source_test.dart b/test/get/switch_source_test.dart index 2dee748..7e56652 100644 --- a/test/get/switch_source_test.dart +++ b/test/get/switch_source_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -11,7 +9,8 @@ void main() { test('re-gets a package if its source has changed', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir('foo', [d.libDir('foo', 'foo 0.0.1'), d.libPubspec('foo', '0.0.1')]).create(); @@ -22,11 +21,15 @@ await pubGet(); - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); }); }
diff --git a/test/get/unknown_sdk_test.dart b/test/get/unknown_sdk_test.dart new file mode 100644 index 0000000..d0c1de3 --- /dev/null +++ b/test/get/unknown_sdk_test.dart
@@ -0,0 +1,25 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:pub/src/exit_codes.dart' as exit_codes; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + test('pub get barks at unknown sdk', () async { + await d.dir(appPath, [ + d.pubspec({ + 'environment': {'foo': '>=1.2.4 <2.0.0'} + }) + ]).create(); + + await pubGet( + error: contains( + "Error on line 1, column 40 of pubspec.yaml: pubspec.yaml refers to an unknown sdk 'foo'."), + exitCode: exit_codes.DATA, + ); + }); +}
diff --git a/test/get/with_empty_environment_test.dart b/test/get/with_empty_environment_test.dart new file mode 100644 index 0000000..30768c4 --- /dev/null +++ b/test/get/with_empty_environment_test.dart
@@ -0,0 +1,27 @@ +// Copyright (c) 2021, 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'; + +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + test(r'runs even with an empty environment (eg. no $HOME)', () async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + + await d.appDir({'foo': 'any'}).create(); + + await pubGet(environment: { + '_PUB_TEST_CONFIG_DIR': null, + if (Platform.isWindows) ...{ + 'SYSTEMROOT': Platform.environment['SYSTEMROOT'], + 'TMP': Platform.environment['TMP'], + }, + }, includeParentEnvironment: false); + }); +}
diff --git a/test/global/activate/activate_git_after_hosted_test.dart b/test/global/activate/activate_git_after_hosted_test.dart index 5dd32c1..c553041 100644 --- a/test/global/activate/activate_git_after_hosted_test.dart +++ b/test/global/activate/activate_git_after_hosted_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,11 +11,10 @@ test('activating a Git package deactivates the hosted one', () async { ensureGit(); - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) + ]); await d.git('foo.git', [ d.libPubspec('foo', '1.0.0'),
diff --git a/test/global/activate/activate_hosted_after_git_test.dart b/test/global/activate/activate_hosted_after_git_test.dart index a86b2cc..1546280 100644 --- a/test/global/activate/activate_hosted_after_git_test.dart +++ b/test/global/activate/activate_hosted_after_git_test.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +10,10 @@ void main() { test('activating a hosted package deactivates the Git one', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '2.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) + ]); await d.git('foo.git', [ d.libPubspec('foo', '1.0.0'), @@ -24,8 +22,9 @@ await runPub(args: ['global', 'activate', '-sgit', '../foo.git']); + final locationUri = p.toUri(p.join(d.sandbox, 'foo.git')); await runPub(args: ['global', 'activate', 'foo'], output: ''' - Package foo is currently active from Git repository "../foo.git". + Package foo is currently active from Git repository "$locationUri". Resolving dependencies... + foo 2.0.0 Downloading foo 2.0.0...
diff --git a/test/global/activate/activate_hosted_after_path_test.dart b/test/global/activate/activate_hosted_after_path_test.dart index 1e01735..4cd753f 100644 --- a/test/global/activate/activate_hosted_after_path_test.dart +++ b/test/global/activate/activate_hosted_after_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -13,11 +11,10 @@ void main() { test('activating a hosted package deactivates the path one', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '2.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) + ]); await d.dir('foo', [ d.libPubspec('foo', '1.0.0'),
diff --git a/test/global/activate/activate_hosted_twice_test.dart b/test/global/activate/activate_hosted_twice_test.dart index 925a205..a4d1337 100644 --- a/test/global/activate/activate_hosted_twice_test.dart +++ b/test/global/activate/activate_hosted_twice_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,7 +9,8 @@ void main() { test('activating a hosted package twice will not precompile', () async { - await servePackages((builder) => builder + final server = await servePackages(); + server ..serve('foo', '1.0.0', deps: { 'bar': 'any' }, contents: [ @@ -23,23 +22,15 @@ ]) ..serve('bar', '1.0.0', contents: [ d.dir('lib', [d.file('bar.dart', 'final version = "1.0.0";')]) - ])); + ]); - await runPub(args: ['global', 'activate', 'foo'], output: ''' -Resolving dependencies... -+ bar 1.0.0 -+ foo 1.0.0 -Downloading foo 1.0.0... -Downloading bar 1.0.0... -Building package executables... -Built foo:foo. -Activated foo 1.0.0.'''); + await runPub(args: ['global', 'activate', 'foo'], output: anything); await runPub(args: ['global', 'activate', 'foo'], output: ''' Package foo is currently active at version 1.0.0. Resolving dependencies... The package foo is already activated at newest available version. -To recompile executables, first run `global deactivate foo`. +To recompile executables, first run `dart pub global deactivate foo`. Activated foo 1.0.0.'''); var pub = await pubRun(global: true, args: ['foo']); @@ -48,10 +39,9 @@ await runPub(args: ['global', 'activate', 'foo']); - globalPackageServer - .add((builder) => builder.serve('bar', '2.0.0', contents: [ - d.dir('lib', [d.file('bar.dart', 'final version = "2.0.0";')]) - ])); + server.serve('bar', '2.0.0', contents: [ + d.dir('lib', [d.file('bar.dart', 'final version = "2.0.0";')]) + ]); await runPub(args: ['global', 'activate', 'foo'], output: ''' Package foo is currently active at version 1.0.0.
diff --git a/test/global/activate/activate_path_after_hosted_test.dart b/test/global/activate/activate_path_after_hosted_test.dart index c73cb01..01d493d 100644 --- a/test/global/activate/activate_path_after_hosted_test.dart +++ b/test/global/activate/activate_path_after_hosted_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -12,12 +10,11 @@ import '../../test_pub.dart'; void main() { - test('activating a hosted package deactivates the path one', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) - ]); - }); + test('activating a path package deactivates the hosted one', () async { + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', "main(args) => print('hosted');")]) + ]); await d.dir('foo', [ d.libPubspec('foo', '2.0.0'),
diff --git a/test/global/activate/bad_version_test.dart b/test/global/activate/bad_version_test.dart index 651c342..c5c4635 100644 --- a/test/global/activate/bad_version_test.dart +++ b/test/global/activate/bad_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/activate/cached_package_test.dart b/test/global/activate/cached_package_test.dart index 7ddcf10..98db402 100644 --- a/test/global/activate/cached_package_test.dart +++ b/test/global/activate/cached_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('can activate an already cached package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')]) + ]); await runPub(args: ['cache', 'add', 'foo']);
diff --git a/test/global/activate/constraint_test.dart b/test/global/activate/constraint_test.dart index b712d00..23386c0 100644 --- a/test/global/activate/constraint_test.dart +++ b/test/global/activate/constraint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,12 +9,11 @@ void main() { test('chooses the highest version that matches the constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.0.1'); - builder.serve('foo', '1.1.0'); - builder.serve('foo', '1.2.3'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.0.1') + ..serve('foo', '1.1.0') + ..serve('foo', '1.2.3'); await runPub(args: ['global', 'activate', 'foo', '<1.1.0']);
diff --git a/test/global/activate/constraint_with_path_test.dart b/test/global/activate/constraint_with_path_test.dart index 1a5beb7..359cd60 100644 --- a/test/global/activate/constraint_with_path_test.dart +++ b/test/global/activate/constraint_with_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/activate/custom_hosted_url_test.dart b/test/global/activate/custom_hosted_url_test.dart index 7443887..8b2f0fc 100644 --- a/test/global/activate/custom_hosted_url_test.dart +++ b/test/global/activate/custom_hosted_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart'; @@ -11,22 +9,21 @@ void main() { test('activating a package from a custom pub server', () async { // The default pub server (i.e. pub.dartlang.org). - await servePackages((builder) { - builder.serve('baz', '1.0.0'); - }); + final server = await servePackages(); + server.serve('baz', '1.0.0'); // The custom pub server. - final customServer = await PackageServer.start((builder) { - Map<String, dynamic> hostedDep(String name, String constraint) => { - 'hosted': { - 'url': builder.serverUrl, - 'name': name, - }, - 'version': constraint, - }; - builder.serve('foo', '1.0.0', deps: {'bar': hostedDep('bar', 'any')}); - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - }); + final customServer = await startPackageServer(); + Map<String, dynamic> hostedDep(String name, String constraint) => { + 'hosted': { + 'url': customServer.url, + 'name': name, + }, + 'version': constraint, + }; + + customServer.serve('foo', '1.0.0', deps: {'bar': hostedDep('bar', 'any')}); + customServer.serve('bar', '1.0.0', deps: {'baz': 'any'}); await runPub( args: ['global', 'activate', 'foo', '-u', customServer.url],
diff --git a/test/global/activate/different_version_test.dart b/test/global/activate/different_version_test.dart index 61ba228..8406b92 100644 --- a/test/global/activate/different_version_test.dart +++ b/test/global/activate/different_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,14 +11,13 @@ test( "discards the previous active version if it doesn't match the " 'constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')]) + await servePackages() + ..serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi");')]) + ]) + ..serve('foo', '2.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi2");')]) ]); - builder.serve('foo', '2.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi2"); ')]) - ]); - }); // Activate 1.0.0. await runPub(args: ['global', 'activate', 'foo', '1.0.0']);
diff --git a/test/global/activate/doesnt_snapshot_path_executables_test.dart b/test/global/activate/doesnt_snapshot_path_executables_test.dart index b809ea7..2ca8d3a 100644 --- a/test/global/activate/doesnt_snapshot_path_executables_test.dart +++ b/test/global/activate/doesnt_snapshot_path_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/activate/empty_constraint_test.dart b/test/global/activate/empty_constraint_test.dart index 9e0bde9..d893bcd 100644 --- a/test/global/activate/empty_constraint_test.dart +++ b/test/global/activate/empty_constraint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,10 +9,9 @@ void main() { test('errors if the constraint matches no versions', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.0.1'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.0.1'); await runPub( args: ['global', 'activate', 'foo', '>1.1.0'],
diff --git a/test/global/activate/feature_test.dart b/test/global/activate/feature_test.dart index 2d30460..58119d1 100644 --- a/test/global/activate/feature_test.dart +++ b/test/global/activate/feature_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - @Skip() import 'package:test/test.dart'; @@ -12,8 +10,8 @@ void main() { test('enables default-on features by default', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} @@ -23,11 +21,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await runPub(args: ['global', 'activate', 'foo'], output: contains(''' Resolving dependencies... @@ -37,8 +33,8 @@ }); test('can enable default-off features', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} @@ -48,11 +44,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await runPub( args: ['global', 'activate', 'foo', '--features', 'things'], @@ -65,8 +59,8 @@ }); test('can disable default-on features', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} @@ -76,11 +70,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await runPub( args: ['global', 'activate', 'foo', '--omit-features', 'stuff'], @@ -91,8 +83,8 @@ }); test('supports multiple arguments', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, @@ -103,11 +95,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await runPub( args: ['global', 'activate', 'foo', '--features', 'things,stuff'], @@ -120,8 +110,8 @@ }); test('can both enable and disable', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} @@ -131,11 +121,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await runPub(args: [ 'global',
diff --git a/test/global/activate/git_package_test.dart b/test/global/activate/git_package_test.dart index 43cd218..ee88de7 100644 --- a/test/global/activate/git_package_test.dart +++ b/test/global/activate/git_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/activate/ignores_active_version_test.dart b/test/global/activate/ignores_active_version_test.dart index d405f54..777a631 100644 --- a/test/global/activate/ignores_active_version_test.dart +++ b/test/global/activate/ignores_active_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,15 +9,14 @@ void main() { test('ignores previously activated version', () async { - await servePackages((builder) { - builder.serve( + await servePackages() + ..serve( 'foo', '1.2.3', - ); - builder.serve('foo', '1.3.0', contents: [ + ) + ..serve('foo', '1.3.0', contents: [ d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')]) ]); - }); // Activate 1.2.3. await runPub(args: ['global', 'activate', 'foo', '1.2.3']);
diff --git a/test/global/activate/installs_dependencies_for_git_test.dart b/test/global/activate/installs_dependencies_for_git_test.dart index 8e5b477..6018f50 100644 --- a/test/global/activate/installs_dependencies_for_git_test.dart +++ b/test/global/activate/installs_dependencies_for_git_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,10 +9,9 @@ void main() { test('activating a Git package installs its dependencies', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - builder.serve('baz', '1.0.0'); - }); + await servePackages() + ..serve('bar', '1.0.0', deps: {'baz': 'any'}) + ..serve('baz', '1.0.0'); await d.git('foo.git', [ d.libPubspec('foo', '1.0.0', deps: {'bar': 'any'}),
diff --git a/test/global/activate/installs_dependencies_for_path_test.dart b/test/global/activate/installs_dependencies_for_path_test.dart index 0afe76e..4688f07 100644 --- a/test/global/activate/installs_dependencies_for_path_test.dart +++ b/test/global/activate/installs_dependencies_for_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,10 +9,9 @@ void main() { test('activating a path package installs dependencies', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - builder.serve('baz', '2.0.0'); - }); + await servePackages() + ..serve('bar', '1.0.0', deps: {'baz': 'any'}) + ..serve('baz', '2.0.0'); await d.dir('foo', [ d.libPubspec('foo', '0.0.0', deps: {'bar': 'any'}),
diff --git a/test/global/activate/installs_dependencies_test.dart b/test/global/activate/installs_dependencies_test.dart index 0b26d8b..770ebcf 100644 --- a/test/global/activate/installs_dependencies_test.dart +++ b/test/global/activate/installs_dependencies_test.dart
@@ -2,19 +2,16 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart'; void main() { test('activating a package installs its dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - builder.serve('baz', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('bar', '1.0.0', deps: {'baz': 'any'}) + ..serve('baz', '1.0.0'); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/activate/missing_git_repo_test.dart b/test/global/activate/missing_git_repo_test.dart index bbb2345..8db65c3 100644 --- a/test/global/activate/missing_git_repo_test.dart +++ b/test/global/activate/missing_git_repo_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/activate/missing_package_arg_test.dart b/test/global/activate/missing_package_arg_test.dart index 5923bd9..588ffcf 100644 --- a/test/global/activate/missing_package_arg_test.dart +++ b/test/global/activate/missing_package_arg_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,8 +10,9 @@ void main() { test('fails if no package was given', () { return runPub( - args: ['global', 'activate'], - error: contains('No package to activate given.'), - exitCode: exit_codes.USAGE); + args: ['global', 'activate'], + error: contains('No package to activate given.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/global/activate/outdated_binstub_test.dart b/test/global/activate/outdated_binstub_test.dart index 43bed90..6d9e298 100644 --- a/test/global/activate/outdated_binstub_test.dart +++ b/test/global/activate/outdated_binstub_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; import '../../test_pub.dart'; -const _OUTDATED_BINSTUB = ''' +const _outdatedBinstub = ''' #!/usr/bin/env sh # This file was created by pub v0.1.2-3. # Package: foo @@ -21,19 +19,17 @@ void main() { test('an outdated binstub is replaced', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'foo-script': 'script'} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'foo-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub(args: ['global', 'activate', 'foo']); await d.dir(cachePath, [ - d.dir('bin', [d.file(binStubName('foo-script'), _OUTDATED_BINSTUB)]) + d.dir('bin', [d.file(binStubName('foo-script'), _outdatedBinstub)]) ]).create(); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/activate/path_package_test.dart b/test/global/activate/path_package_test.dart index 5153760..514176a 100644 --- a/test/global/activate/path_package_test.dart +++ b/test/global/activate/path_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -57,14 +55,13 @@ }); test("Doesn't precompile binaries when activating from path", () async { - await servePackages( - (builder) => builder.serve( - 'bar', - '1.0.0', - contents: [ - d.dir('bin', [d.file('bar.dart', "main() => print('bar');")]) - ], - ), + final server = await servePackages(); + server.serve( + 'bar', + '1.0.0', + contents: [ + d.dir('bin', [d.file('bar.dart', "main() => print('bar');")]) + ], ); await d.dir('foo', [
diff --git a/test/global/activate/reactivating_git_upgrades_test.dart b/test/global/activate/reactivating_git_upgrades_test.dart index 0ccbb65..68102da 100644 --- a/test/global/activate/reactivating_git_upgrades_test.dart +++ b/test/global/activate/reactivating_git_upgrades_test.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -31,11 +30,12 @@ await d.git('foo.git', [d.libPubspec('foo', '1.0.1')]).commit(); // Activating it again pulls down the latest commit. + final locationUri = p.toUri(p.join(d.sandbox, 'foo.git')); await runPub( args: ['global', 'activate', '-sgit', '../foo.git'], output: allOf( startsWith('Package foo is currently active from Git repository ' - '"../foo.git".\n' + '"$locationUri".\n' 'Resolving dependencies...\n' '+ foo 1.0.1 from git ../foo.git at '), // Specific revision number goes here.
diff --git a/test/global/activate/removes_old_lockfile_test.dart b/test/global/activate/removes_old_lockfile_test.dart deleted file mode 100644 index 7d7a9e0..0000000 --- a/test/global/activate/removes_old_lockfile_test.dart +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright (c) 2014, 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. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('removes the 1.6-style lockfile', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); - - await d.dir(cachePath, [ - d.dir('global_packages', [ - d.file( - 'foo.lock', - 'packages: {foo: {description: foo, source: hosted, ' - 'version: "1.0.0"}}}') - ]) - ]).create(); - - await runPub(args: ['global', 'activate', 'foo']); - - await d.dir(cachePath, [ - d.dir('global_packages', [ - d.nothing('foo.lock'), - d.dir('foo', [d.file('pubspec.lock', contains('1.0.0'))]) - ]) - ]).validate(); - }); -}
diff --git a/test/global/activate/snapshots_git_executables_test.dart b/test/global/activate/snapshots_git_executables_test.dart index 81a0152..aee6a71 100644 --- a/test/global/activate/snapshots_git_executables_test.dart +++ b/test/global/activate/snapshots_git_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/activate/snapshots_hosted_executables_test.dart b/test/global/activate/snapshots_hosted_executables_test.dart index e9d2a2d..bc2b332 100644 --- a/test/global/activate/snapshots_hosted_executables_test.dart +++ b/test/global/activate/snapshots_hosted_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,16 +9,15 @@ void main() { test('snapshots the executables for a hosted package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [ - d.file('hello.dart', "void main() => print('hello!');"), - d.file('goodbye.dart', "void main() => print('goodbye!');"), - d.file('shell.sh', 'echo shell'), - d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")]) - ]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [ + d.file('hello.dart', "void main() => print('hello!');"), + d.file('goodbye.dart', "void main() => print('goodbye!');"), + d.file('shell.sh', 'echo shell'), + d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")]) + ]) + ]); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/activate/supports_version_solver_backtracking_test.dart b/test/global/activate/supports_version_solver_backtracking_test.dart index e43e735..c8c138d 100644 --- a/test/global/activate/supports_version_solver_backtracking_test.dart +++ b/test/global/activate/supports_version_solver_backtracking_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,14 +9,13 @@ void main() { test('performs verison solver backtracking if necessary', () async { - await servePackages((builder) { - builder.serve('foo', '1.1.0', pubspec: { + await servePackages() + ..serve('foo', '1.1.0', pubspec: { 'environment': {'sdk': '>=0.1.2 <0.2.0'} - }); - builder.serve('foo', '1.2.0', pubspec: { + }) + ..serve('foo', '1.2.0', pubspec: { 'environment': {'sdk': '>=0.1.3 <0.2.0'} }); - }); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/activate/uncached_package_test.dart b/test/global/activate/uncached_package_test.dart index 3bdb185..1a18d70 100644 --- a/test/global/activate/uncached_package_test.dart +++ b/test/global/activate/uncached_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,17 +9,16 @@ void main() { test('installs and activates the best version of a package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi"); ')]) + await servePackages() + ..serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi");')]) + ]) + ..serve('foo', '1.2.3', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi 1.2.3");')]) + ]) + ..serve('foo', '2.0.0-wildly.unstable', contents: [ + d.dir('bin', [d.file('foo.dart', 'main() => print("hi unstable");')]) ]); - builder.serve('foo', '1.2.3', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi 1.2.3"); ')]) - ]); - builder.serve('foo', '2.0.0-wildly.unstable', contents: [ - d.dir('bin', [d.file('foo.dart', 'main() => print("hi unstable"); ')]) - ]); - }); await runPub(args: ['global', 'activate', 'foo'], output: ''' Resolving dependencies...
diff --git a/test/global/activate/unexpected_arguments_test.dart b/test/global/activate/unexpected_arguments_test.dart index d7bb4cf..be6633d 100644 --- a/test/global/activate/unexpected_arguments_test.dart +++ b/test/global/activate/unexpected_arguments_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/activate/unknown_package_test.dart b/test/global/activate/unknown_package_test.dart index 6a4fe84..271545d 100644 --- a/test/global/activate/unknown_package_test.dart +++ b/test/global/activate/unknown_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,7 +9,7 @@ void main() { test('errors if the package could not be found', () async { - await serveNoPackages(); + await servePackages(); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/binstub_runs_executable_test.dart b/test/global/binstubs/binstub_runs_executable_test.dart index 284729b..98ab53b 100644 --- a/test/global/binstubs/binstub_runs_executable_test.dart +++ b/test/global/binstubs/binstub_runs_executable_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:test_process/test_process.dart'; @@ -14,14 +12,12 @@ void main() { test('the generated binstub runs a snapshotted executable', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'foo-script': 'script'} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'foo-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/binstubs/binstub_runs_global_run_if_no_snapshot_test.dart b/test/global/binstubs/binstub_runs_global_run_if_no_snapshot_test.dart index 25a6281..8024c3a 100644 --- a/test/global/binstubs/binstub_runs_global_run_if_no_snapshot_test.dart +++ b/test/global/binstubs/binstub_runs_global_run_if_no_snapshot_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart b/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart index f59d8e2..cd477db 100644 --- a/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart +++ b/test/global/binstubs/binstub_runs_precompiled_snapshot_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,13 +9,12 @@ void main() { test('the binstubs runs a built snapshot if present', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'foo-script': 'script'} - }, contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'foo-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/binstubs/creates_executables_in_pubspec_test.dart b/test/global/binstubs/creates_executables_in_pubspec_test.dart index 1529d3e..a6604ab 100644 --- a/test/global/binstubs/creates_executables_in_pubspec_test.dart +++ b/test/global/binstubs/creates_executables_in_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,17 +9,16 @@ void main() { test('creates binstubs for each executable in the pubspec', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'one': null, 'two-renamed': 'second'} - }, contents: [ - d.dir('bin', [ - d.file('one.dart', "main(args) => print('one');"), - d.file('second.dart', "main(args) => print('two');"), - d.file('nope.dart', "main(args) => print('nope');") - ]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'one': null, 'two-renamed': 'second'} + }, contents: [ + d.dir('bin', [ + d.file('one.dart', "main(args) => print('one');"), + d.file('second.dart', "main(args) => print('two');"), + d.file('nope.dart', "main(args) => print('nope');") + ]) + ]); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/does_not_warn_if_no_executables_test.dart b/test/global/binstubs/does_not_warn_if_no_executables_test.dart index e172b1b..9814f15 100644 --- a/test/global/binstubs/does_not_warn_if_no_executables_test.dart +++ b/test/global/binstubs/does_not_warn_if_no_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,12 +9,10 @@ void main() { test('does not warn if the package has no executables', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/binstubs/does_not_warn_if_on_path_test.dart b/test/global/binstubs/does_not_warn_if_on_path_test.dart index 07cba16..9b11386 100644 --- a/test/global/binstubs/does_not_warn_if_on_path_test.dart +++ b/test/global/binstubs/does_not_warn_if_on_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -14,14 +12,12 @@ void main() { test('does not warn if the binstub directory is on the path', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'script': null} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'script': null} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); // Add the test's cache bin directory to the path. var binDir = p.dirname(Platform.executable);
diff --git a/test/global/binstubs/explicit_and_no_executables_options_test.dart b/test/global/binstubs/explicit_and_no_executables_options_test.dart index d493bd7..68bbd5b 100644 --- a/test/global/binstubs/explicit_and_no_executables_options_test.dart +++ b/test/global/binstubs/explicit_and_no_executables_options_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/binstubs/explicit_executables_test.dart b/test/global/binstubs/explicit_executables_test.dart index e032c32..e721f73 100644 --- a/test/global/binstubs/explicit_executables_test.dart +++ b/test/global/binstubs/explicit_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/missing_script_test.dart b/test/global/binstubs/missing_script_test.dart index 96b5e89..433f9cf 100644 --- a/test/global/binstubs/missing_script_test.dart +++ b/test/global/binstubs/missing_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart';
diff --git a/test/global/binstubs/name_collision_test.dart b/test/global/binstubs/name_collision_test.dart index 54afc02..75b72ce 100644 --- a/test/global/binstubs/name_collision_test.dart +++ b/test/global/binstubs/name_collision_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/name_collision_with_overwrite_test.dart b/test/global/binstubs/name_collision_with_overwrite_test.dart index caed6d1..6e5a869 100644 --- a/test/global/binstubs/name_collision_with_overwrite_test.dart +++ b/test/global/binstubs/name_collision_with_overwrite_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/no_executables_flag_test.dart b/test/global/binstubs/no_executables_flag_test.dart index d7bc037..39f91cd 100644 --- a/test/global/binstubs/no_executables_flag_test.dart +++ b/test/global/binstubs/no_executables_flag_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart b/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart index f4cd075..442dfbc 100644 --- a/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart +++ b/test/global/binstubs/outdated_binstub_runs_pub_global_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -15,7 +13,7 @@ import 'utils.dart'; /// The contents of the binstub for [executable], or `null` if it doesn't exist. -String binStub(String executable) { +String? binStub(String executable) { final f = File(p.join(d.sandbox, cachePath, 'bin', binStubName(executable))); if (f.existsSync()) { return f.readAsStringSync(); @@ -26,23 +24,22 @@ void main() { test("an outdated binstub runs 'pub global run', which replaces old binstub", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': { - 'foo-script': 'script', - 'foo-script2': 'script', - 'foo-script-not-installed': 'script', - 'foo-another-script': 'another-script', - 'foo-another-script-not-installed': 'another-script' - } - }, contents: [ - d.dir('bin', [ - d.file('script.dart', r"main(args) => print('ok $args');"), - d.file('another-script.dart', - r"main(args) => print('not so good $args');") - ]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': { + 'foo-script': 'script', + 'foo-script2': 'script', + 'foo-script-not-installed': 'script', + 'foo-another-script': 'another-script', + 'foo-another-script-not-installed': 'another-script' + } + }, contents: [ + d.dir('bin', [ + d.file('script.dart', r"main(args) => print('ok $args');"), + d.file( + 'another-script.dart', r"main(args) => print('not so good $args');") + ]) + ]); await runPub(args: [ 'global',
diff --git a/test/global/binstubs/outdated_snapshot_test.dart b/test/global/binstubs/outdated_snapshot_test.dart index c1181b9..91bfff6 100644 --- a/test/global/binstubs/outdated_snapshot_test.dart +++ b/test/global/binstubs/outdated_snapshot_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -15,14 +13,12 @@ void main() { test("a binstub runs 'pub global run' for an outdated snapshot", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'foo-script': 'script'} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'foo-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/binstubs/path_package_test.dart b/test/global/binstubs/path_package_test.dart index d702054..0461e35 100644 --- a/test/global/binstubs/path_package_test.dart +++ b/test/global/binstubs/path_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/reactivate_removes_old_executables_test.dart b/test/global/binstubs/reactivate_removes_old_executables_test.dart index e7f6ade..80b50ff 100644 --- a/test/global/binstubs/reactivate_removes_old_executables_test.dart +++ b/test/global/binstubs/reactivate_removes_old_executables_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/removes_even_if_not_in_pubspec_test.dart b/test/global/binstubs/removes_even_if_not_in_pubspec_test.dart index ed215ae..4cd458e 100644 --- a/test/global/binstubs/removes_even_if_not_in_pubspec_test.dart +++ b/test/global/binstubs/removes_even_if_not_in_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/binstubs/removes_when_deactivated_test.dart b/test/global/binstubs/removes_when_deactivated_test.dart index d241f27..975defe 100644 --- a/test/global/binstubs/removes_when_deactivated_test.dart +++ b/test/global/binstubs/removes_when_deactivated_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,16 +9,15 @@ void main() { test('removes binstubs when the package is deactivated', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'one': null, 'two': null} - }, contents: [ - d.dir('bin', [ - d.file('one.dart', "main(args) => print('one');"), - d.file('two.dart', "main(args) => print('two');") - ]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'one': null, 'two': null} + }, contents: [ + d.dir('bin', [ + d.file('one.dart', "main(args) => print('one');"), + d.file('two.dart', "main(args) => print('two');") + ]) + ]); await runPub(args: ['global', 'activate', 'foo']); await runPub(args: ['global', 'deactivate', 'foo']);
diff --git a/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart b/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart index d53af96..99eeaaf 100644 --- a/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart +++ b/test/global/binstubs/runs_once_even_when_dart_is_batch_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -16,18 +14,17 @@ test( 'runs only once even when dart on path is a batch file (as in flutter/bin)', () async { - await servePackages((builder) { - builder.serve( - 'foo', - '1.0.0', - contents: [ - d.dir('bin', [d.file('script.dart', 'main(args) => print(args);')]), - ], - pubspec: { - 'executables': {'script': 'script'}, - }, - ); - }); + final server = await servePackages(); + server.serve( + 'foo', + '1.0.0', + contents: [ + d.dir('bin', [d.file('script.dart', 'main(args) => print(args);')]), + ], + pubspec: { + 'executables': {'script': 'script'}, + }, + ); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/binstubs/unknown_explicit_executable_test.dart b/test/global/binstubs/unknown_explicit_executable_test.dart index 0b27527..33b82e7 100644 --- a/test/global/binstubs/unknown_explicit_executable_test.dart +++ b/test/global/binstubs/unknown_explicit_executable_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/global/binstubs/utils.dart b/test/global/binstubs/utils.dart index e2346cc..59a8df0 100644 --- a/test/global/binstubs/utils.dart +++ b/test/global/binstubs/utils.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -16,7 +14,7 @@ /// /// The `pub`/`pub.bat` command on the PATH will be the one in tool/test-bin not /// the one from the sdk. -Map getEnvironment() { +Map<String, String> getEnvironment() { var binDir = p.dirname(Platform.resolvedExecutable); var separator = Platform.isWindows ? ';' : ':'; var pubBin = p.absolute('tool', 'test-bin');
diff --git a/test/global/binstubs/warns_if_not_on_path_test.dart b/test/global/binstubs/warns_if_not_on_path_test.dart index fcfdb0c..d98bf76 100644 --- a/test/global/binstubs/warns_if_not_on_path_test.dart +++ b/test/global/binstubs/warns_if_not_on_path_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,14 +9,12 @@ void main() { test('warns if the binstub directory is not on the path', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'executables': {'some-dart-script': 'script'} - }, contents: [ - d.dir( - 'bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'executables': {'some-dart-script': 'script'} + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok \$args');")]) + ]); await runPub( args: ['global', 'activate', 'foo'],
diff --git a/test/global/deactivate/deactivate_and_reactivate_package_test.dart b/test/global/deactivate/deactivate_and_reactivate_package_test.dart index ffad990..da33486 100644 --- a/test/global/deactivate/deactivate_and_reactivate_package_test.dart +++ b/test/global/deactivate/deactivate_and_reactivate_package_test.dart
@@ -2,18 +2,15 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart'; void main() { test('activates a different version after deactivating', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0'); // Activate an old version. await runPub(args: ['global', 'activate', 'foo', '1.0.0']);
diff --git a/test/global/deactivate/git_package_test.dart b/test/global/deactivate/git_package_test.dart index 3aa047d..7fc2855 100644 --- a/test/global/deactivate/git_package_test.dart +++ b/test/global/deactivate/git_package_test.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:path/path.dart' as p; import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -20,9 +19,10 @@ await runPub(args: ['global', 'activate', '-sgit', '../foo.git']); + final locationUri = p.toUri(p.join(d.sandbox, 'foo.git')); await runPub( args: ['global', 'deactivate', 'foo'], output: - 'Deactivated package foo 1.0.0 from Git repository "../foo.git".'); + 'Deactivated package foo 1.0.0 from Git repository "$locationUri".'); }); }
diff --git a/test/global/deactivate/hosted_package_test.dart b/test/global/deactivate/hosted_package_test.dart index 884e70f..fa91829 100644 --- a/test/global/deactivate/hosted_package_test.dart +++ b/test/global/deactivate/hosted_package_test.dart
@@ -2,15 +2,14 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../test_pub.dart'; void main() { test('deactivates an active hosted package', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/deactivate/missing_package_arg_test.dart b/test/global/deactivate/missing_package_arg_test.dart index 7d41b82..8de8ab1 100644 --- a/test/global/deactivate/missing_package_arg_test.dart +++ b/test/global/deactivate/missing_package_arg_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,13 +9,10 @@ void main() { test('fails if no package was given', () { - return runPub(args: ['global', 'deactivate'], error: ''' - No package to deactivate given. - - Usage: pub global deactivate <package> - -h, --help Print this usage information. - - Run "pub help" to see global options. - ''', exitCode: exit_codes.USAGE); + return runPub( + args: ['global', 'deactivate'], + error: contains('No package to deactivate given.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/global/deactivate/path_package_test.dart b/test/global/deactivate/path_package_test.dart index f28d8d1..1f50713 100644 --- a/test/global/deactivate/path_package_test.dart +++ b/test/global/deactivate/path_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart';
diff --git a/test/global/deactivate/removes_precompiled_snapshots_test.dart b/test/global/deactivate/removes_precompiled_snapshots_test.dart index 7d075b3..a7670e2 100644 --- a/test/global/deactivate/removes_precompiled_snapshots_test.dart +++ b/test/global/deactivate/removes_precompiled_snapshots_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,7 +9,8 @@ void main() { test('removes built snapshots', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0')); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/deactivate/unexpected_arguments_test.dart b/test/global/deactivate/unexpected_arguments_test.dart index d5748f2..dd1f11f 100644 --- a/test/global/deactivate/unexpected_arguments_test.dart +++ b/test/global/deactivate/unexpected_arguments_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,13 +10,9 @@ void main() { test('fails if there are extra arguments', () { return runPub( - args: ['global', 'deactivate', 'foo', 'bar', 'baz'], error: ''' - Unexpected arguments "bar" and "baz". - - Usage: pub global deactivate <package> - -h, --help Print this usage information. - - Run "pub help" to see global options. - ''', exitCode: exit_codes.USAGE); + args: ['global', 'deactivate', 'foo', 'bar', 'baz'], + error: contains('Unexpected arguments "bar" and "baz".'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/global/deactivate/unknown_package_test.dart b/test/global/deactivate/unknown_package_test.dart index ad0973e..35023ad 100644 --- a/test/global/deactivate/unknown_package_test.dart +++ b/test/global/deactivate/unknown_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,7 +9,7 @@ void main() { test('errors if the package is not activated', () async { - await serveNoPackages(); + await servePackages(); await runPub( args: ['global', 'deactivate', 'foo'],
diff --git a/test/global/list_test.dart b/test/global/list_test.dart index 8b7293a..00ca22c 100644 --- a/test/global/list_test.dart +++ b/test/global/list_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; @@ -14,9 +12,8 @@ void main() { test('lists an activated hosted package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await runPub(args: ['global', 'activate', 'foo']); @@ -33,9 +30,10 @@ await runPub(args: ['global', 'activate', '-sgit', '../foo.git']); + final locationUri = p.toUri(p.join(d.sandbox, 'foo.git')); await runPub( args: ['global', 'list'], - output: 'foo 1.0.0 from Git repository "../foo.git"'); + output: 'foo 1.0.0 from Git repository "$locationUri"'); }); test('lists an activated Path package', () async { @@ -51,11 +49,10 @@ }); test('lists activated packages in alphabetical order', () async { - await servePackages((builder) { - builder.serve('aaa', '1.0.0'); - builder.serve('bbb', '1.0.0'); - builder.serve('ccc', '1.0.0'); - }); + await servePackages() + ..serve('aaa', '1.0.0') + ..serve('bbb', '1.0.0') + ..serve('ccc', '1.0.0'); await runPub(args: ['global', 'activate', 'ccc']); await runPub(args: ['global', 'activate', 'aaa']);
diff --git a/test/global/run/errors_if_outside_bin_test.dart b/test/global/run/errors_if_outside_bin_test.dart index 497f26a..72bcd4f 100644 --- a/test/global/run/errors_if_outside_bin_test.dart +++ b/test/global/run/errors_if_outside_bin_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,27 +10,17 @@ void main() { test('errors if the script is in a subdirectory.', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('example', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('example', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']); - await runPub(args: ['global', 'run', 'foo:example/script'], error: ''' -Cannot run an executable in a subdirectory of a global package. - -Usage: pub global run <package>:<executable> [args...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. (Will disable - snapshotting, resulting in slower - startup). - --[no-]sound-null-safety Override the default null safety - execution mode. - -Run "pub help" to see global options. -''', exitCode: exit_codes.USAGE); + await runPub( + args: ['global', 'run', 'foo:example/script'], + error: contains( + 'Cannot run an executable in a subdirectory of a global package.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart b/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart index 73b5556..3bef340 100644 --- a/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart +++ b/test/global/run/fails_if_sdk_constraint_is_unmet_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,11 +10,10 @@ void main() { test("fails if the current SDK doesn't match the constraint", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']); @@ -43,15 +40,14 @@ }); test('fails if SDK is downgraded below the constraints', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'environment': { - 'sdk': '>=2.0.0 <3.0.0', - }, - }, contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'environment': { + 'sdk': '>=2.0.0 <3.0.0', + }, + }, contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")]) + ]); await runPub( environment: {'_PUB_TEST_SDK_VERSION': '2.0.0'}, @@ -71,8 +67,8 @@ }); test('fails if SDK is downgraded below dependency SDK constraints', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: { 'bar': '^1.0.0', }, pubspec: { 'environment': { @@ -80,13 +76,12 @@ }, }, contents: [ d.dir('bin', [d.file('script.dart', "main(args) => print('123-OK');")]) - ]); - builder.serve('bar', '1.0.0', pubspec: { + ]) + ..serve('bar', '1.0.0', pubspec: { 'environment': { 'sdk': '>=2.2.0 <3.0.0', }, }); - }); await runPub( environment: {'_PUB_TEST_SDK_VERSION': '2.2.0'},
diff --git a/test/global/run/implicit_executable_name_test.dart b/test/global/run/implicit_executable_name_test.dart index a2f8c12..9757772 100644 --- a/test/global/run/implicit_executable_name_test.dart +++ b/test/global/run/implicit_executable_name_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('defaults to the package name if the script is omitted', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('foo.dart', "main(args) => print('foo');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('foo.dart', "main(args) => print('foo');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/missing_executable_arg_test.dart b/test/global/run/missing_executable_arg_test.dart index 2bb8ec8..b64d387 100644 --- a/test/global/run/missing_executable_arg_test.dart +++ b/test/global/run/missing_executable_arg_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,20 +9,10 @@ void main() { test('fails if no executable was given', () { - return runPub(args: ['global', 'run'], error: ''' -Must specify an executable to run. - -Usage: pub global run <package>:<executable> [args...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. (Will disable - snapshotting, resulting in slower - startup). - --[no-]sound-null-safety Override the default null safety - execution mode. - -Run "pub help" to see global options. -''', exitCode: exit_codes.USAGE); + return runPub( + args: ['global', 'run'], + error: contains('Must specify an executable to run.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/global/run/missing_path_package_test.dart b/test/global/run/missing_path_package_test.dart index f15d976..99cf30a 100644 --- a/test/global/run/missing_path_package_test.dart +++ b/test/global/run/missing_path_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart';
diff --git a/test/global/run/nonexistent_script_test.dart b/test/global/run/nonexistent_script_test.dart index dc0a738..8ff0a42 100644 --- a/test/global/run/nonexistent_script_test.dart +++ b/test/global/run/nonexistent_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -12,9 +10,10 @@ void main() { test('errors if the script does not exist.', () async { - await servePackages((builder) => builder.serve('foo', '1.0.0', pubspec: { - 'dev_dependencies': {'bar': '1.0.0'} - })); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'dev_dependencies': {'bar': '1.0.0'} + }); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/package_api_test.dart b/test/global/run/package_api_test.dart index c95fc5b..5db401b 100644 --- a/test/global/run/package_api_test.dart +++ b/test/global/run/package_api_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -12,10 +10,9 @@ void main() { test('an immutable application sees a file: package config', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - - builder.serve('foo', '1.0.0', deps: { + await servePackages() + ..serve('bar', '1.0.0') + ..serve('foo', '1.0.0', deps: { 'bar': '1.0.0' }, contents: [ d.dir('bin', [ @@ -33,7 +30,6 @@ """) ]) ]); - }); await runPub(args: ['global', 'activate', 'foo']); @@ -45,12 +41,12 @@ 'global_packages/foo/.dart_tool/package_config.json'); expect(pub.stdout, emits(p.toUri(packageConfigPath).toString())); - var fooResourcePath = p.join( - globalPackageServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt'); + var fooResourcePath = + p.join(globalServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt'); expect(pub.stdout, emits(p.toUri(fooResourcePath).toString())); - var barResourcePath = p.join( - globalPackageServer.pathInCache('bar', '1.0.0'), 'lib/resource.txt'); + var barResourcePath = + p.join(globalServer.pathInCache('bar', '1.0.0'), 'lib/resource.txt'); expect(pub.stdout, emits(p.toUri(barResourcePath).toString())); await pub.shouldExit(0); });
diff --git a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart index 4ace362..24e65bf 100644 --- a/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart +++ b/test/global/run/recompiles_if_snapshot_is_out_of_date_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -13,11 +11,10 @@ void main() { test('recompiles a script if the snapshot is out-of-date', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/reflects_changes_to_local_package_test.dart b/test/global/run/reflects_changes_to_local_package_test.dart index 5bc9e55..864111b 100644 --- a/test/global/run/reflects_changes_to_local_package_test.dart +++ b/test/global/run/reflects_changes_to_local_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/run/runs_git_script_test.dart b/test/global/run/runs_git_script_test.dart index 8d120b4..900b586 100644 --- a/test/global/run/runs_git_script_test.dart +++ b/test/global/run/runs_git_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/run/runs_path_script_test.dart b/test/global/run/runs_path_script_test.dart index 90db648..7cc90d4 100644 --- a/test/global/run/runs_path_script_test.dart +++ b/test/global/run/runs_path_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/global/run/runs_script_in_checked_mode_test.dart b/test/global/run/runs_script_in_checked_mode_test.dart index 1b399c5..d0511cf 100644 --- a/test/global/run/runs_script_in_checked_mode_test.dart +++ b/test/global/run/runs_script_in_checked_mode_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('runs a script with assertions enabled', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', 'main() { assert(false); }')]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', 'main() { assert(false); }')]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/runs_script_in_unchecked_mode_test.dart b/test/global/run/runs_script_in_unchecked_mode_test.dart index 005bad3..ca752b2 100644 --- a/test/global/run/runs_script_in_unchecked_mode_test.dart +++ b/test/global/run/runs_script_in_unchecked_mode_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; import '../../test_pub.dart'; -const SCRIPT = ''' +const _script = ''' main() { assert(false); print("no checks"); @@ -18,11 +16,10 @@ void main() { test('runs a script in unchecked mode by default', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', SCRIPT)]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', _script)]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/runs_script_test.dart b/test/global/run/runs_script_test.dart index bab4d1c..f3f0e99 100644 --- a/test/global/run/runs_script_test.dart +++ b/test/global/run/runs_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,10 @@ void main() { test('runs a script in an activated package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/runs_script_without_packages_file_test.dart b/test/global/run/runs_script_without_packages_file_test.dart index aa5e691..dc225ba 100644 --- a/test/global/run/runs_script_without_packages_file_test.dart +++ b/test/global/run/runs_script_without_packages_file_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -14,11 +12,10 @@ void main() { test('runs a snapshotted script without a .dart_tool/package_config file', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', "main(args) => print('ok');")]) + ]); await runPub(args: ['global', 'activate', 'foo']);
diff --git a/test/global/run/unknown_package_test.dart b/test/global/run/unknown_package_test.dart index 55a875a..adcb666 100644 --- a/test/global/run/unknown_package_test.dart +++ b/test/global/run/unknown_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -11,7 +9,7 @@ void main() { test('errors if the package is not activated', () async { - await serveNoPackages(); + await servePackages(); await runPub( args: ['global', 'run', 'foo:bar'],
diff --git a/test/global/run/uses_old_lockfile_test.dart b/test/global/run/uses_old_lockfile_test.dart deleted file mode 100644 index 4ae12ef..0000000 --- a/test/global/run/uses_old_lockfile_test.dart +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright (c) 2014, 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. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('uses the 1.6-style lockfile if necessary', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - builder.serve('foo', '1.0.0', deps: { - 'bar': 'any' - }, contents: [ - d.dir('bin', [ - d.file('script.dart', """ - import 'package:bar/bar.dart' as bar; - - main(args) => print(bar.main());""") - ]) - ]); - }); - - await runPub(args: ['cache', 'add', 'foo']); - await runPub(args: ['cache', 'add', 'bar']); - - await d.dir(cachePath, [ - d.dir('global_packages', [ - d.file('foo.lock', ''' -packages: - foo: - description: foo - source: hosted - version: "1.0.0" - bar: - description: bar - source: hosted - version: "1.0.0"''') - ]) - ]).create(); - - var pub = await pubRun(global: true, args: ['foo:script']); - expect(pub.stdout, emitsThrough('bar 1.0.0')); - await pub.shouldExit(); - - await d.dir(cachePath, [ - d.dir('global_packages', [ - d.nothing('foo.lock'), - d.dir('foo', [d.file('pubspec.lock', contains('1.0.0'))]) - ]) - ]).validate(); - }); -}
diff --git a/test/golden_file.dart b/test/golden_file.dart index 055c5c5..7927776 100644 --- a/test/golden_file.dart +++ b/test/golden_file.dart
@@ -2,35 +2,210 @@ // 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. -// @dart=2.10 - +import 'dart:async'; import 'dart:io'; -import 'package:path/path.dart' as path; +import 'package:path/path.dart' as p; +import 'package:pub/src/ascii_tree.dart' as ascii_tree; +import 'package:pub/src/io.dart'; +import 'package:stack_trace/stack_trace.dart' show Trace; import 'package:test/test.dart'; -/// Will test [actual] against the contests of the file at [goldenFilePath]. -/// -/// If the file doesn't exist, the file is instead created containing [actual]. -void expectMatchesGoldenFile(String actual, String goldenFilePath) { - var goldenFile = File(goldenFilePath); - if (goldenFile.existsSync()) { - expect( - actual, equals(goldenFile.readAsStringSync().replaceAll('\r\n', '\n')), - reason: 'goldenFilePath: "$goldenFilePath"'); - } else { - // This enables writing the updated file when run in otherwise hermetic - // settings. - // - // This is to make updating the golden files easier in a bazel environment - // See https://docs.bazel.build/versions/2.0.0/user-manual.html#run . - final workspaceDirectory = - Platform.environment['BUILD_WORKSPACE_DIRECTORY']; - if (workspaceDirectory != null) { - goldenFile = File(path.join(workspaceDirectory, goldenFilePath)); - } - goldenFile - ..createSync(recursive: true) - ..writeAsStringSync(actual); +import 'ascii_tree_test.dart'; +import 'descriptor.dart' as d; +import 'test_pub.dart'; + +final _isCI = () { + final p = RegExp(r'^1|(?:true)$', caseSensitive: false); + final ci = Platform.environment['CI']; + return ci != null && ci.isNotEmpty && p.hasMatch(ci); +}(); + +/// Find the current `_test.dart` filename invoked from stack-trace. +String _findCurrentTestFilename() => Trace.current() + .frames + .lastWhere( + (frame) => + frame.uri.isScheme('file') && + p.basename(frame.uri.toFilePath()).endsWith('_test.dart'), + ) + .uri + .toFilePath(); + +class GoldenTestContext { + static const _endOfSection = '' + '--------------------------------' + ' END OF OUTPUT ' + '---------------------------------\n\n'; + + late final String _currentTestFile; + late final String _testName; + + late String _goldenFilePath; + late File _goldenFile; + late String _header; + final _results = <String>[]; + late bool _goldenFileExists; + bool _generatedNewData = false; // track if new data is generated + int _nextSectionIndex = 0; + + GoldenTestContext._(this._currentTestFile, this._testName) { + final rel = p.relative( + _currentTestFile.replaceAll(RegExp(r'\.dart$'), ''), + from: p.join(p.current, 'test'), + ); + _goldenFilePath = p.join( + 'test', + 'testdata', + 'goldens', + rel, + // Sanitize the name, and add .txt + _testName.replaceAll(RegExp(r'[<>:"/\|?*%#]'), '~') + '.txt', + ); + _goldenFile = File(_goldenFilePath); + _header = '# GENERATED BY: ${p.relative(_currentTestFile)}\n\n'; } + + void _readGoldenFile() { + _goldenFileExists = _goldenFile.existsSync(); + + // Read the golden file for this test + if (_goldenFileExists) { + var text = _goldenFile.readAsStringSync().replaceAll('\r\n', '\n'); + // Strip header line + if (text.startsWith('#') && text.contains('\n\n')) { + text = text.substring(text.indexOf('\n\n') + 2); + } + _results.addAll(text.split(_endOfSection)); + } + } + + /// Expect section [sectionIndex] to match [actual]. + void _expectSection(int sectionIndex, String actual) { + if (_goldenFileExists && + _results.length > sectionIndex && + _results[sectionIndex].isNotEmpty) { + expect( + actual, + equals(_results[sectionIndex]), + reason: 'Expect matching section $sectionIndex from "$_goldenFilePath"', + ); + } else { + while (_results.length <= sectionIndex) { + _results.add(''); + } + _results[sectionIndex] = actual; + _generatedNewData = true; + } + } + + void _writeGoldenFile() { + // If we generated new data, then we need to write a new file, and fail the + // test case, or mark it as skipped. + if (_generatedNewData) { + // This enables writing the updated file when run in otherwise hermetic + // settings. + // + // This is to make updating the golden files easier in a bazel environment + // See https://docs.bazel.build/versions/2.0.0/user-manual.html#run . + var goldenFile = _goldenFile; + final workspaceDirectory = + Platform.environment['BUILD_WORKSPACE_DIRECTORY']; + if (workspaceDirectory != null) { + goldenFile = File(p.join(workspaceDirectory, _goldenFilePath)); + } + goldenFile + ..createSync(recursive: true) + ..writeAsStringSync(_header + _results.join(_endOfSection)); + + // If running in CI we should fail if the golden file doesn't already + // exist, or is missing entries. + // This typically happens if we forgot to commit a file to git. + if (_isCI) { + fail('Missing golden file: "$_goldenFilePath", ' + 'try running tests again and commit the file'); + } else { + // If not running in CI, then we consider the test as skipped, we've + // generated the file, but the user should run the tests again. + // Or push to CI in which case we'll run the tests again anyways. + markTestSkipped( + 'Generated golden file: "$_goldenFilePath" instead of running test', + ); + } + } + } + + /// Expect the next section in the golden file to match [actual]. + /// + /// This will create the section if it is missing. + /// + /// **Warning**: Take care when using this in an async context, sections are + /// numbered based on the other in which calls are made. Hence, ensure + /// consistent ordering of calls. + void expectNextSection(String actual) => + _expectSection(_nextSectionIndex++, actual); + + /// Run `pub` [args] with [environment] variables in [workingDirectory], and + /// log stdout/stderr and exitcode to golden file. + Future<void> run( + List<String> args, { + Map<String, String>? environment, + String? workingDirectory, + }) async { + // Create new section index number (before doing anything async) + final sectionIndex = _nextSectionIndex++; + final s = StringBuffer(); + s.writeln('## Section $sectionIndex'); + await runPubIntoBuffer( + args, + s, + environment: environment, + workingDirectory: workingDirectory, + ); + + _expectSection(sectionIndex, s.toString()); + } + + /// Log directory tree structure under [directory] to golden file. + Future<void> tree([String? directory]) async { + // Create new section index number (before doing anything async) + final sectionIndex = _nextSectionIndex++; + + final target = p.join(d.sandbox, directory ?? '.'); + + final s = StringBuffer(); + s.writeln('## Section $sectionIndex'); + if (directory != null) { + s.writeln('\$ cd $directory'); + } + s.writeln('\$ tree'); + s.writeln(stripColors(ascii_tree.fromFiles( + listDir(target, recursive: true), + baseDir: target, + ))); + + _expectSection(sectionIndex, s.toString()); + } +} + +/// Create a [test] with [GoldenTestContext] which allows running golden tests. +/// +/// This will create a golden file containing output of calls to: +/// * [GoldenTestContext.run] +/// * [GoldenTestContext.tree] +/// +/// The golden file with the recorded output will be created at: +/// `test/testdata/goldens/path/to/myfile_test/<name>.txt` +/// , when `path/to/myfile_test.dart` is the `_test.dart` file from which this +/// function is called. +void testWithGolden( + String name, + FutureOr<void> Function(GoldenTestContext ctx) fn, +) { + final ctx = GoldenTestContext._(_findCurrentTestFilename(), name); + test(name, () async { + ctx._readGoldenFile(); + await fn(ctx); + ctx._writeGoldenFile(); + }); }
diff --git a/test/goldens/directory_option.txt b/test/goldens/directory_option.txt deleted file mode 100644 index 356480c..0000000 --- a/test/goldens/directory_option.txt +++ /dev/null
@@ -1,84 +0,0 @@ -$ pub add --directory=myapp foo -Resolving dependencies in myapp... -+ foo 1.0.0 -Changed 1 dependency in myapp! - -$ pub -C myapp add bar -Resolving dependencies in myapp... -+ bar 1.2.3 -Changed 1 dependency in myapp! - -$ pub -C myapp/example get --directory=myapp bar -Resolving dependencies in myapp... -Got dependencies in myapp! - -$ pub remove bar -C myapp -Resolving dependencies in myapp... -These packages are no longer being depended on: -- bar 1.2.3 -Changed 1 dependency in myapp! - -$ pub get bar -C myapp -Resolving dependencies in myapp... -Got dependencies in myapp! - -$ pub get bar -C myapp/example -Resolving dependencies in myapp/example... -+ foo 1.0.0 -+ test_pkg 1.0.0 from path myapp -Changed 2 dependencies in myapp/example! - -$ pub get bar -C myapp/example2 -Resolving dependencies in myapp/example2... -[ERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp". -[ERR] ╷ -[ERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dartlang.org","description":"A package, I guess.","environment":{"sdk":">=1.8.0 <=2.0.0"}, dependencies: { foo: ^1.0.0}} -[ERR] │ ^^^^^^^^^^ -[ERR] ╵ -[Exit code] 65 - -$ pub get bar -C myapp/broken_dir -[ERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp/broken_dir". -[Exit code] 66 - -$ pub downgrade -C myapp -Resolving dependencies in myapp... - foo 1.0.0 -No dependencies changed in myapp. - -$ pub upgrade bar -C myapp -Resolving dependencies in myapp... - foo 1.0.0 -No dependencies changed in myapp. - -$ pub run -C myapp bin/app.dart -Building package executable... -Built test_pkg:app. -Hi - -$ pub publish -C myapp --dry-run -Publishing test_pkg 1.0.0 to http://localhost:$PORT: -|-- CHANGELOG.md -|-- LICENSE -|-- README.md -|-- bin -| '-- app.dart -|-- example -| '-- pubspec.yaml -|-- example2 -| '-- pubspec.yaml -|-- lib -| '-- test_pkg.dart -'-- pubspec.yaml -The server may enforce additional checks. -[ERR] -[ERR] Package has 0 warnings. - -$ pub uploader -C myapp add sigurdm@google.com -Good job! - -$ pub deps -C myapp -Dart SDK 1.12.0 -test_pkg 1.0.0 -'-- foo 1.0.0 -
diff --git a/test/goldens/help.txt b/test/goldens/help.txt deleted file mode 100644 index 10997b4..0000000 --- a/test/goldens/help.txt +++ /dev/null
@@ -1,386 +0,0 @@ -[command] -> pub add --help -[stdout] -Add a dependency to pubspec.yaml. - -Usage: pub add <package>[:<constraint>] [options] --h, --help Print this usage information. --d, --dev Adds package to the development dependencies instead. - --git-url Git URL of the package - --git-ref Git branch or commit to be retrieved - --git-path Path of git package in repository - --hosted-url URL of package host server - --path Local path - --sdk SDK source for package - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - --[no-]precompile Build executables in immediate dependencies. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-add for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub build --help -[stdout] -Deprecated command - -Usage: pub build <subcommand> [arguments...] --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub cache --help -[stdout] -Work with the system cache. - -Usage: pub cache [arguments...] --h, --help Print this usage information. - -Available subcommands: - add Install a package. - repair Reinstall cached packages. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub cache add --help -[stdout] -Install a package. - -Usage: pub cache add <package> [--version <constraint>] [--all] --h, --help Print this usage information. - --all Install all matching versions. --v, --version Version constraint. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub cache list --help -[stdout] -List packages in the system cache. - -Usage: pub cache list <subcommand> [arguments...] --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub cache repair --help -[stdout] -Reinstall cached packages. - -Usage: pub cache repair <subcommand> [arguments...] --h, --help Print this usage information. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub deps --help -[stdout] -Print package dependencies. - -Usage: pub deps [arguments...] --h, --help Print this usage information. --s, --style How output should be displayed. - [compact, tree (default), list] - --[no-]dev Whether to include dev dependencies. - (defaults to on) - --executables List all available executables. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-deps for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub downgrade --help -[stdout] -Downgrade the current package's dependencies to oldest versions. - -This doesn't modify the lockfile, so it can be reset with "pub get". - -Usage: pub downgrade [dependencies...] --h, --help Print this usage information. - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-downgrade for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub global --help -[stdout] -Work with global packages. - -Usage: pub global [arguments...] --h, --help Print this usage information. - -Available subcommands: - activate Make a package's executables globally available. - deactivate Remove a previously activated package. - list List globally activated packages. - run Run an executable from a globally activated package. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub get --help -[stdout] -Get the current package's dependencies. - -Usage: pub get <subcommand> [arguments...] --h, --help Print this usage information. - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - --[no-]precompile Build executables in immediate dependencies. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub list-package-dirs --help -[stdout] -Print local paths to dependencies. - -Usage: pub list-package-dirs --h, --help Print this usage information. - --format How output should be displayed. - [json] - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub publish --help -[stdout] -Publish the current package to pub.dartlang.org. - -Usage: pub publish [options] --h, --help Print this usage information. --n, --dry-run Validate but do not publish the package. --f, --force Publish without confirmation if there are no errors. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub outdated --help -[stdout] -Analyze your dependencies to find which ones can be upgraded. - -Usage: pub outdated [options] --h, --help Print this usage information. - --[no-]color Whether to color the output. - Defaults to color when connected to a - terminal, and no-color otherwise. - --[no-]dependency-overrides Show resolutions with `dependency_overrides`. - (defaults to on) - --[no-]dev-dependencies Take dev dependencies into account. - (defaults to on) - --json Output the results using a json format. - --mode=<PROPERTY> Highlight versions with PROPERTY. - Only packages currently missing that PROPERTY - will be included unless --show-all. - [outdated (default), null-safety] - --[no-]prereleases Include prereleases in latest version. - (defaults to on in --mode=null-safety). - --[no-]show-all Include dependencies that are already - fullfilling --mode. - --[no-]transitive Show transitive dependencies. - (defaults to off in --mode=null-safety). - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub remove --help -[stdout] -Removes a dependency from the current package. - -Usage: pub remove <package> --h, --help Print this usage information. - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - --[no-]precompile Build executables in immediate dependencies. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-remove for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub run --help -[stdout] -Run an executable from a package. - -Usage: pub run <executable> [arguments...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. - (Will disable snapshotting, resulting in - slower startup). - --[no-]sound-null-safety Override the default null safety - execution mode. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub serve --help -[stdout] -Deprecated command - -Usage: pub serve <subcommand> [arguments...] --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub upgrade --help -[stdout] -Upgrade the current package's dependencies to latest versions. - -Usage: pub upgrade [dependencies...] --h, --help Print this usage information. - --[no-]offline Use cached packages instead of accessing the network. --n, --dry-run Report what dependencies would change but don't change - any. - --[no-]precompile Build executables in immediate dependencies. - --null-safety Upgrade constraints in pubspec.yaml to null-safety - versions - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-upgrade for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub uploader --help -[stdout] -Manage uploaders for a package on pub.dartlang.org. - -Usage: pub uploader [options] {add/remove} <email> --h, --help Print this usage information. - --package The package whose uploaders will be modified. - (defaults to the current package) - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub login --help -[stdout] -Log into pub.dev. - -Usage: pub login --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub logout --help -[stdout] -Log out of pub.dev. - -Usage: pub logout <subcommand> [arguments...] --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 - -[command] -> pub version --help -[stdout] -Print pub version. - -Usage: pub version --h, --help Print this usage information. - -Run "pub help" to see global options. -[stderr] - -[exitCode] -0 -
diff --git a/test/goldens/upgrade_major_versions_example.txt b/test/goldens/upgrade_major_versions_example.txt deleted file mode 100644 index 448a874..0000000 --- a/test/goldens/upgrade_major_versions_example.txt +++ /dev/null
@@ -1,21 +0,0 @@ -$ pub upgrade --major-versions --example -Resolving dependencies... -+ bar 2.0.0 -Changed 1 dependency! - -Changed 1 constraint in pubspec.yaml: - bar: ^1.0.0 -> ^2.0.0 -Resolving dependencies in ./example... -Got dependencies in ./example. -[ERR] Running `upgrade --major-versions` only in `.`. Run `dart pub upgrade --major-versions --directory example/` separately. - -$ pub upgrade --major-versions --directory example -Resolving dependencies in example... - bar 2.0.0 -> foo 2.0.0 (was 1.0.0) - myapp 0.0.0 from path . -Changed 1 dependency in example! - -Changed 1 constraint in pubspec.yaml: - foo: ^1.0.0 -> ^2.0.0 -
diff --git a/test/goldens/usage_exception.txt b/test/goldens/usage_exception.txt deleted file mode 100644 index 5c7ead7..0000000 --- a/test/goldens/usage_exception.txt +++ /dev/null
@@ -1,66 +0,0 @@ -[command] -> pub -[stdout] -Pub is a package manager for Dart. - -Usage: pub <command> [arguments] - -Global options: --h, --help Print this usage information. - --version Print pub version. - --[no-]trace Print debugging information when an error occurs. - --verbosity Control output verbosity. - - [all] Show all output including internal tracing messages. - [error] Show only errors. - [io] Also show IO operations. - [normal] Show errors, warnings, and user messages. - [solver] Show steps during version resolution. - [warning] Show only errors and warnings. - --v, --verbose Shortcut for "--verbosity=all". - -Available commands: - add Add a dependency to pubspec.yaml. - cache Work with the system cache. - deps Print package dependencies. - downgrade Downgrade the current package's dependencies to oldest versions. - get Get the current package's dependencies. - global Work with global packages. - login Log into pub.dev. - logout Log out of pub.dev. - outdated Analyze your dependencies to find which ones can be upgraded. - publish Publish the current package to pub.dartlang.org. - remove Removes a dependency from the current package. - run Run an executable from a package. - upgrade Upgrade the current package's dependencies to latest versions. - uploader Manage uploaders for a package on pub.dartlang.org. - version Print pub version. - -Run "pub help <command>" for more information about a command. -See https://dart.dev/tools/pub/cmd for detailed documentation. -[stderr] - -[exitCode] -0 - -[command] -> pub global -[stdout] - -[stderr] -Missing subcommand for "pub global". - -Usage: pub global [arguments...] --h, --help Print this usage information. - -Available subcommands: - activate Make a package's executables globally available. - deactivate Remove a previously activated package. - list List globally activated packages. - run Run an executable from a globally activated package. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. -[exitCode] -64
diff --git a/test/goldens/version.txt b/test/goldens/version.txt deleted file mode 100644 index a093c93..0000000 --- a/test/goldens/version.txt +++ /dev/null
@@ -1,17 +0,0 @@ -[command] -> pub --version -[stdout] -Pub 0.1.2+3 -[stderr] - -[exitCode] -0 - -[command] -> pub version -[stdout] -Pub 0.1.2+3 -[stderr] - -[exitCode] -0
diff --git a/test/help_test.dart b/test/help_test.dart new file mode 100644 index 0000000..e66f8a4 --- /dev/null +++ b/test/help_test.dart
@@ -0,0 +1,46 @@ +// Copyright (c) 2021, 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 'package:args/command_runner.dart'; +import 'package:pub/src/command_runner.dart' show PubCommandRunner; + +import 'golden_file.dart'; + +/// Extract all commands and subcommands. +/// +/// Result will be an iterable of lists, illustrated as follows: +/// ``` +/// [ +/// [pub] +/// [pub, get] +/// ... +/// ] +/// ``` +Iterable<List<String>> _extractCommands( + List<String> parents, + Iterable<Command> cmds, +) sync* { + if (parents.isNotEmpty) { + yield parents; + } + // Track that we don't add more than once, we don't want to test aliases + final names = <String>{}; + yield* cmds + .where((sub) => !sub.hidden && names.add(sub.name)) + .map((sub) => _extractCommands( + [...parents, sub.name], + sub.subcommands.values, + )) + .expand((cmds) => cmds); +} + +/// Tests for `pub ... --help`. +Future<void> main() async { + final cmds = _extractCommands([], PubCommandRunner().commands.values); + for (final c in cmds) { + testWithGolden('pub ${c.join(' ')} --help', (ctx) async { + await ctx.run([...c, '--help']); + }); + } +}
diff --git a/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart b/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart index f5ad35c..7fb22a3 100644 --- a/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart +++ b/test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -11,6 +9,7 @@ import 'package:test/test.dart'; import '../descriptor.dart' as d; +import '../golden_file.dart'; import '../test_pub.dart'; void main() { @@ -18,15 +17,18 @@ test( 'fails gracefully if the package server responds with broken package listings', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); - globalPackageServer.extraHandlers[RegExp('/api/packages/.*')] = - expectAsync1((request) { - expect(request.method, 'GET'); - return Response(200, - body: jsonEncode({ - 'notTheRight': {'response': 'type'} - })); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect( + 'GET', + RegExp('/api/packages/.*'), + expectAsync1((request) { + return Response(200, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }), + ); await d.appDir({'foo': '1.2.3'}).create(); await pubCommand(command, @@ -38,4 +40,80 @@ exitCode: exit_codes.DATA); }); }); + + testWithGolden('bad_json', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect('GET', RegExp('/api/packages/.*'), (request) { + return Response(200, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }); + await d.appDir({'foo': '1.2.3'}).create(); + + await ctx.run(['get']); + }); + + testWithGolden('403', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect('GET', RegExp('/api/packages/.*'), (request) { + return Response(403, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }); + await d.appDir({'foo': '1.2.3'}).create(); + + await ctx.run(['get']); + }); + + testWithGolden('401', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect('GET', RegExp('/api/packages/.*'), (request) { + return Response(401, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }); + await d.appDir({'foo': '1.2.3'}).create(); + + await ctx.run(['get']); + }); + + testWithGolden('403-with-message', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect('GET', RegExp('/api/packages/.*'), (request) { + return Response(403, + headers: { + 'www-authenticate': 'Bearer realm="pub", message="<message>"', + }, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }); + await d.appDir({'foo': '1.2.3'}).create(); + + await ctx.run(['get']); + }); + + testWithGolden('401-with-message', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3'); + server.expect('GET', RegExp('/api/packages/.*'), (request) { + return Response(401, + headers: { + 'www-authenticate': 'Bearer realm="pub", message="<message>"', + }, + body: jsonEncode({ + 'notTheRight': {'response': 'type'} + })); + }); + await d.appDir({'foo': '1.2.3'}).create(); + + await ctx.run(['get']); + }); }
diff --git a/test/hosted/fail_gracefully_on_invalid_url_test.dart b/test/hosted/fail_gracefully_on_invalid_url_test.dart index 9cbfbe8..94922c0 100644 --- a/test/hosted/fail_gracefully_on_invalid_url_test.dart +++ b/test/hosted/fail_gracefully_on_invalid_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/hosted/fail_gracefully_on_missing_package_test.dart b/test/hosted/fail_gracefully_on_missing_package_test.dart index 882d11c..7c6290d 100644 --- a/test/hosted/fail_gracefully_on_missing_package_test.dart +++ b/test/hosted/fail_gracefully_on_missing_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -13,7 +11,7 @@ void main() { forBothPubGetAndUpgrade((command) { test('fails gracefully if the package does not exist', () async { - await serveNoPackages(); + await servePackages(); await d.appDir({'foo': '1.2.3'}).create();
diff --git a/test/hosted/fail_gracefully_on_url_resolve_test.dart b/test/hosted/fail_gracefully_on_url_resolve_test.dart index 9e3abcd..7a91e7a 100644 --- a/test/hosted/fail_gracefully_on_url_resolve_test.dart +++ b/test/hosted/fail_gracefully_on_url_resolve_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/hosted/fail_gracefully_with_hint_test.dart b/test/hosted/fail_gracefully_with_hint_test.dart new file mode 100644 index 0000000..4f1a326 --- /dev/null +++ b/test/hosted/fail_gracefully_with_hint_test.dart
@@ -0,0 +1,64 @@ +// Copyright (c) 2012, 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 'package:pub/src/exit_codes.dart' as exit_codes; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../golden_file.dart'; +import '../test_pub.dart'; + +void main() { + testWithGolden('hint: try without --offline', (ctx) async { + // Run the server so that we know what URL to use in the system cache. + (await servePackages()).serveErrors(); + + await d.appDir({'foo': 'any'}).create(); + + await pubGet( + args: ['--offline'], + exitCode: exit_codes.UNAVAILABLE, + error: contains('Try again without --offline!'), + ); + }); + + testWithGolden('supports two hints', (ctx) async { + // Run the server so that we know what URL to use in the system cache. + (await servePackages()).serveErrors(); + + await d.hostedCache([ + d.dir('foo-1.2.3', [ + d.pubspec({ + 'name': 'foo', + 'version': '1.2.3', + 'environment': { + 'flutter': 'any', // generates hint -> flutter pub get + }, + }), + ]), + d.dir('foo-1.2.4', [ + d.pubspec({ + 'name': 'foo', + 'version': '1.2.4', + 'dependencies': { + 'bar': 'any', // generates hint -> try without --offline + }, + }), + ]), + ]).create(); + + await d.appDir({'foo': 'any'}).create(); + + await pubGet( + args: ['--offline'], + exitCode: exit_codes.UNAVAILABLE, + error: allOf( + contains('Try again without --offline!'), + contains('flutter pub get'), // hint that + ), + ); + + await ctx.run(['get', '--offline']); + }); +}
diff --git a/test/hosted/metadata_test.dart b/test/hosted/metadata_test.dart index 6ba59f5..c705ac7 100644 --- a/test/hosted/metadata_test.dart +++ b/test/hosted/metadata_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:test/test.dart'; @@ -14,9 +12,8 @@ void main() { forBothPubGetAndUpgrade((command) { test('sends metadata headers for a direct dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); @@ -35,9 +32,8 @@ }); test('sends metadata headers for a dev dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -61,9 +57,8 @@ }); test('sends metadata headers for a transitive dependency', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - }); + final server = await servePackages(); + server.serve('bar', '1.0.0'); await d.appDir({ 'foo': {'path': '../foo'} @@ -84,9 +79,8 @@ }); test("doesn't send metadata headers to a foreign server", () async { - var server = await PackageServer.start((builder) { - builder.serve('foo', '1.0.0'); - }); + var server = await startPackageServer() + ..serve('foo', '1.0.0'); await d.appDir({ 'foo': { @@ -99,9 +93,7 @@ }); test("doesn't send metadata headers when CI=true", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + (await servePackages()).serve('foo', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create();
diff --git a/test/hosted/offline_test.dart b/test/hosted/offline_test.dart index ef738c8..ca3dc80 100644 --- a/test/hosted/offline_test.dart +++ b/test/hosted/offline_test.dart
@@ -2,22 +2,19 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -Future<void> populateCache(Map<String, List<String>> versions) async { - await servePackages((b) { - for (final entry in versions.entries) { - for (final version in entry.value) { - b.serve(entry.key, version); - } +Future<void> populateCache( + Map<String, List<String>> versions, PackageServer server) async { + for (final entry in versions.entries) { + for (final version in entry.value) { + server.serve(entry.key, version); } - }); + } for (final entry in versions.entries) { for (final version in entry.value) { await d.appDir({entry.key: version}).create(); @@ -29,37 +26,41 @@ void main() { forBothPubGetAndUpgrade((command) { test('upgrades a package using the cache', () async { + final server = await servePackages(); await populateCache({ 'foo': ['1.2.2', '1.2.3'], 'bar': ['1.2.3'] - }); + }, server); // Now serve only errors - to validate we are truly offline. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); - String warning; + String? warning; if (command == RunCommand.upgrade) { warning = 'Warning: Upgrading when offline may not update you ' 'to the latest versions of your dependencies.'; } await pubCommand(command, args: ['--offline'], warning: warning); - - await d.appPackagesFile({'foo': '1.2.3', 'bar': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + d.packageConfigEntry(name: 'bar', version: '1.2.3'), + ]).validate(); }); test('supports prerelease versions', () async { + final server = await servePackages(); await populateCache({ 'foo': ['1.2.3-alpha.1'] - }); + }, server); // Now serve only errors - to validate we are truly offline. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': 'any'}).create(); - String warning; + String? warning; if (command == RunCommand.upgrade) { warning = 'Warning: Upgrading when offline may not update you ' 'to the latest versions of your dependencies.'; @@ -67,12 +68,15 @@ await pubCommand(command, args: ['--offline'], warning: warning); - await d.appPackagesFile({'foo': '1.2.3-alpha.1'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3-alpha.1'), + ]).validate(); }); test('fails gracefully if a dependency is not cached', () async { // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + final server = await servePackages(); + server.serveErrors(); await d.appDir({'foo': 'any'}).create(); @@ -82,16 +86,19 @@ error: equalsIgnoringWhitespace(""" Because myapp depends on foo any which doesn't exist (could not find package foo in cache), version solving failed. + + Try again without --offline! """)); }); test('fails gracefully if no cached versions match', () async { + final server = await servePackages(); await populateCache({ 'foo': ['1.2.2', '1.2.3'] - }); + }, server); // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': '>2.0.0'}).create(); @@ -105,8 +112,10 @@ test( 'fails gracefully if a dependency is not cached and a lockfile ' 'exists', () async { + final server = await servePackages(); + // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': 'any'}).create(); @@ -118,15 +127,19 @@ error: equalsIgnoringWhitespace(""" Because myapp depends on foo any which doesn't exist (could not find package foo in cache), version solving failed. + + Try again without --offline! """)); }); test('downgrades to the version in the cache if necessary', () async { + final server = await servePackages(); + await populateCache({ 'foo': ['1.2.2', '1.2.3'] - }); + }, server); // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + server.serveErrors(); await d.appDir({'foo': 'any'}).create(); @@ -134,15 +147,19 @@ await pubCommand(command, args: ['--offline']); - await d.appPackagesFile({'foo': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.3'), + ]).validate(); }); test('skips invalid cached versions', () async { + final server = await servePackages(); + await populateCache({ 'foo': ['1.2.2', '1.2.3'] - }); + }, server); // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + server.serveErrors(); await d.hostedCache([ d.dir('foo-1.2.3', [d.file('pubspec.yaml', '{')]), @@ -153,15 +170,19 @@ await pubCommand(command, args: ['--offline']); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); }); test('skips invalid locked versions', () async { + final server = await servePackages(); + await populateCache({ 'foo': ['1.2.2', '1.2.3'] - }); + }, server); // Run the server so that we know what URL to use in the system cache. - await serveErrors(); + server.serveErrors(); await d.hostedCache([ d.dir('foo-1.2.3', [d.file('pubspec.yaml', '{')]) @@ -173,7 +194,9 @@ await pubCommand(command, args: ['--offline']); - await d.appPackagesFile({'foo': '1.2.2'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.2.2'), + ]).validate(); }); }); }
diff --git a/test/hosted/remove_removed_dependency_test.dart b/test/hosted/remove_removed_dependency_test.dart index 9d530d7..a0446c0 100644 --- a/test/hosted/remove_removed_dependency_test.dart +++ b/test/hosted/remove_removed_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -12,22 +10,25 @@ void main() { forBothPubGetAndUpgrade((command) { test("removes a dependency that's removed from the pubspec", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('bar', '1.0.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubCommand(command); - - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); await d.appDir({'foo': 'any'}).create(); await pubCommand(command); - await d.appPackagesFile({'foo': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + ]).validate(); }); }); }
diff --git a/test/hosted/remove_removed_transitive_dependency_test.dart b/test/hosted/remove_removed_transitive_dependency_test.dart index 43ac01c..182ec3f 100644 --- a/test/hosted/remove_removed_transitive_dependency_test.dart +++ b/test/hosted/remove_removed_transitive_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -14,31 +12,30 @@ test( "removes a transitive dependency that's no longer depended " 'on', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'}); - builder.serve('bar', '1.0.0', - deps: {'shared_dep': 'any', 'bar_dep': 'any'}); - builder.serve('shared_dep', '1.0.0'); - builder.serve('bar_dep', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'}) + ..serve('bar', '1.0.0', deps: {'shared_dep': 'any', 'bar_dep': 'any'}) + ..serve('shared_dep', '1.0.0') + ..serve('bar_dep', '1.0.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubCommand(command); - - await d.appPackagesFile({ - 'foo': '1.0.0', - 'bar': '1.0.0', - 'shared_dep': '1.0.0', - 'bar_dep': '1.0.0', - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'), + d.packageConfigEntry(name: 'bar_dep', version: '1.0.0'), + ]).validate(); await d.appDir({'foo': 'any'}).create(); await pubCommand(command); - await d - .appPackagesFile({'foo': '1.0.0', 'shared_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'), + ]).validate(); }); }); }
diff --git a/test/hosted/short_syntax_test.dart b/test/hosted/short_syntax_test.dart new file mode 100644 index 0000000..5d4cf28 --- /dev/null +++ b/test/hosted/short_syntax_test.dart
@@ -0,0 +1,89 @@ +// Copyright (c) 2021, 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'; + +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + setUp(() async { + final server = await servePackages(); + server.serve('foo', '1.2.3', pubspec: { + 'environment': {'sdk': '^2.0.0'} + }); + }); + forBothPubGetAndUpgrade((command) { + Future<void> testWith(dynamic dependency) async { + await d.dir(appPath, [ + d.libPubspec( + 'app', + '1.0.0', + deps: {'foo': dependency}, + sdk: '^2.15.0', + ), + ]).create(); + + await pubCommand( + command, + exitCode: 0, + environment: {'_PUB_TEST_SDK_VERSION': '2.15.0'}, + ); + + final lockFile = loadYaml( + await File(p.join(d.sandbox, appPath, 'pubspec.lock')).readAsString(), + ); + + expect(lockFile['packages']['foo'], { + 'dependency': 'direct main', + 'source': 'hosted', + 'description': { + 'name': 'foo', + 'url': globalServer.url, + }, + 'version': '1.2.3', + }); + } + + test('supports hosted: <url> syntax', () async { + return testWith({'hosted': globalServer.url}); + }); + + test('supports hosted map without name', () { + return testWith({ + 'hosted': {'url': globalServer.url}, + }); + }); + + test('interprets hosted string as name for older versions', () async { + await d.dir(appPath, [ + d.libPubspec( + 'app', + '1.0.0', + deps: { + 'foo': {'hosted': 'foo', 'version': '^1.2.3'} + }, + sdk: '^2.0.0', + ), + ]).create(); + + await pubCommand( + command, + exitCode: 0, + environment: {'_PUB_TEST_SDK_VERSION': '2.15.0'}, + ); + + final lockFile = loadYaml( + await File(p.join(d.sandbox, appPath, 'pubspec.lock')).readAsString(), + ); + + expect( + lockFile['packages']['foo']['description']['url'], globalServer.url); + }); + }); +}
diff --git a/test/hosted/version_negotiation_test.dart b/test/hosted/version_negotiation_test.dart index 3d12703..44dbe7a 100644 --- a/test/hosted/version_negotiation_test.dart +++ b/test/hosted/version_negotiation_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -18,11 +16,11 @@ await d.appDir({ 'foo': { - 'hosted': {'name': 'foo', 'url': globalPackageServer.url} + 'hosted': {'name': 'foo', 'url': globalServer.url} } }).create(); - globalPackageServer.expect('GET', '/api/packages/foo', (request) { + globalServer.expect('GET', '/api/packages/foo', (request) { expect( request.headers['accept'], equals('application/vnd.pub.v2+json')); return shelf.Response(404); @@ -37,13 +35,13 @@ await d.appDir({ 'foo': { - 'hosted': {'name': 'foo', 'url': globalPackageServer.url} + 'hosted': {'name': 'foo', 'url': globalServer.url} } }).create(); var pub = await startPub(args: [command.name]); - globalPackageServer.expect( + globalServer.expect( 'GET', '/api/packages/foo', (request) => shelf.Response(406)); await pub.shouldExit(1);
diff --git a/test/hosted/will_normalize_hosted_url_test.dart b/test/hosted/will_normalize_hosted_url_test.dart index f2da266..6cc3888 100644 --- a/test/hosted/will_normalize_hosted_url_test.dart +++ b/test/hosted/will_normalize_hosted_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:http/http.dart' as http; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:shelf/shelf.dart'; @@ -15,47 +13,50 @@ void main() { forBothPubGetAndUpgrade((command) { test('does not require slash on bare domain', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); - // All the tests in this file assumes that [globalPackageServer.url] + final server = await servePackages(); + server.serve('foo', '1.2.3'); + // All the tests in this file assumes that [globalServer.url] // will be on the form: // http://localhost:<port> // In particular, that it doesn't contain anything path segment. - expect(Uri.parse(globalPackageServer.url).path, isEmpty); + expect(Uri.parse(globalServer.url).path, isEmpty); await d.dir(appPath, [ d.appPubspec({ 'foo': { - 'hosted': {'name': 'foo', 'url': globalPackageServer.url}, + 'hosted': {'name': 'foo', 'url': globalServer.url}, }, }), ]).create(); await pubCommand( command, - silent: contains('${globalPackageServer.url}/api/packages/foo'), + silent: contains('${globalServer.url}/api/packages/foo'), ); }); test('normalizes extra slash', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir(appPath, [ d.appPubspec({ 'foo': { - 'hosted': {'name': 'foo', 'url': globalPackageServer.url + '/'}, + 'hosted': {'name': 'foo', 'url': globalServer.url + '/'}, }, }), ]).create(); await pubCommand( command, - silent: contains('${globalPackageServer.url}/api/packages/foo'), + silent: contains('${globalServer.url}/api/packages/foo'), ); }); test('cannot normalize double slash', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); - globalPackageServer.expect( + final server = await servePackages(); + server.serve('foo', '1.2.3'); + globalServer.expect( 'GET', '//api/packages/foo', (request) => Response.notFound(''), @@ -64,15 +65,14 @@ await d.dir(appPath, [ d.appPubspec({ 'foo': { - 'hosted': {'name': 'foo', 'url': globalPackageServer.url + '//'}, + 'hosted': {'name': 'foo', 'url': globalServer.url + '//'}, }, }), ]).create(); await pubCommand( command, - error: contains( - 'could not find package foo at ${globalPackageServer.url}//'), + error: contains('could not find package foo at ${globalServer.url}//'), exitCode: exit_codes.UNAVAILABLE, ); }); @@ -82,27 +82,31 @@ /// This is a bit of a hack, to easily test if hosted pub URLs with a path /// segment works and if the slashes are normalized. void _proxyMyFolderToRoot() { - globalPackageServer.extraHandlers[RegExp('/my-folder/.*')] = (r) async { - if (r.method != 'GET' && r.method != 'HEAD') { - return Response.forbidden(null); - } - final path = r.requestedUri.path.substring('/my-folder/'.length); - final res = await http.get( - Uri.parse(globalPackageServer.url + '/$path'), - ); - return Response(res.statusCode, body: res.bodyBytes, headers: { - 'Content-Type': res.headers['Content-Type'], - }); - }; + globalServer.handle( + RegExp('/my-folder/.*'), + (r) async { + if (r.method != 'GET' && r.method != 'HEAD') { + return Response.forbidden(null); + } + final path = r.requestedUri.path.substring('/my-folder/'.length); + final res = await http.get( + Uri.parse(globalServer.url + '/$path'), + ); + return Response(res.statusCode, body: res.bodyBytes, headers: { + 'Content-Type': res.headers['content-type']!, + }); + }, + ); } test('will use normalized url with path', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); _proxyMyFolderToRoot(); // testing with a normalized URL - final testUrl = globalPackageServer.url + '/my-folder/'; - final normalizedUrl = globalPackageServer.url + '/my-folder/'; + final testUrl = globalServer.url + '/my-folder/'; + final normalizedUrl = globalServer.url + '/my-folder/'; await d.dir(appPath, [ d.appPubspec({ @@ -120,12 +124,13 @@ }); test('will normalize url with path by adding slash', () async { - await servePackages((b) => b..serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); _proxyMyFolderToRoot(); // Testing with a URL that is missing the slash. - final testUrl = globalPackageServer.url + '/my-folder'; - final normalizedUrl = globalPackageServer.url + '/my-folder/'; + final testUrl = globalServer.url + '/my-folder'; + final normalizedUrl = globalServer.url + '/my-folder/'; await d.dir(appPath, [ d.appPubspec({
diff --git a/test/ignore_test.dart b/test/ignore_test.dart index 75238b5..a8ab8ac 100644 --- a/test/ignore_test.dart +++ b/test/ignore_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:pub/src/ignore.dart'; @@ -41,10 +39,10 @@ return [path.substring(0, nextSlash == -1 ? path.length : nextSlash)]; } - Ignore ignoreForDir(String dir) => c.patterns[dir] == null + Ignore? ignoreForDir(String dir) => c.patterns[dir] == null ? null : Ignore( - c.patterns[dir], + c.patterns[dir]!, onInvalidPattern: (_, __) => hasWarning = true, ignoreCase: ignoreCase, ); @@ -87,17 +85,18 @@ for (final c in testData) { c.paths.forEach((path, expected) { - if (c.ignoreCase == null) { + var ignoreCase = c.ignoreCase; + if (ignoreCase == null) { _testIgnorePath(c, path, expected, false); _testIgnorePath(c, path, expected, true); } else { - _testIgnorePath(c, path, expected, c.ignoreCase); + _testIgnorePath(c, path, expected, ignoreCase); } }); } }); - ProcessResult runGit(List<String> args, {String workingDirectory}) { + ProcessResult runGit(List<String> args, {String? workingDirectory}) { final executable = Platform.isWindows ? 'cmd' : 'git'; args = Platform.isWindows ? ['/c', 'git', ...args] : args; return Process.runSync(executable, args, @@ -105,24 +104,24 @@ } group('git', () { - Directory tmp; + Directory? tmp; setUpAll(() async { tmp = await Directory.systemTemp.createTemp('package-ignore-test-'); - final ret = runGit(['init'], workingDirectory: tmp.path); + final ret = runGit(['init'], workingDirectory: tmp!.path); expect(ret.exitCode, equals(0), reason: 'Running "git init" failed. StdErr: ${ret.stderr} StdOut: ${ret.stdout}'); }); tearDownAll(() async { - await tmp.delete(recursive: true); + await tmp!.delete(recursive: true); tmp = null; }); tearDown(() async { - runGit(['clean', '-f', '-d', '-x'], workingDirectory: tmp.path); + runGit(['clean', '-f', '-d', '-x'], workingDirectory: tmp!.path); }); void _testIgnorePath( @@ -137,7 +136,7 @@ expect( runGit( ['config', '--local', 'core.ignoreCase', ignoreCase.toString()], - workingDirectory: tmp.path, + workingDirectory: tmp!.path, ).exitCode, anyOf(0, 1), reason: 'Running "git config --local core.ignoreCase ..." failed', @@ -145,17 +144,17 @@ for (final directory in c.patterns.keys) { final resolvedDirectory = - directory == '' ? tmp.uri : tmp.uri.resolve(directory + '/'); + directory == '' ? tmp!.uri : tmp!.uri.resolve(directory + '/'); Directory.fromUri(resolvedDirectory).createSync(recursive: true); final gitIgnore = File.fromUri(resolvedDirectory.resolve('.gitignore')); gitIgnore.writeAsStringSync( - c.patterns[directory].join('\n') + '\n', + c.patterns[directory]!.join('\n') + '\n', ); } final process = runGit( - ['-C', tmp.path, 'check-ignore', '--no-index', path], - workingDirectory: tmp.path); + ['-C', tmp!.path, 'check-ignore', '--no-index', path], + workingDirectory: tmp!.path); expect(process.exitCode, anyOf(0, 1), reason: 'Running "git check-ignore" failed'); final ignored = process.exitCode == 0; @@ -172,11 +171,12 @@ for (final c in testData) { c.paths.forEach((path, expected) { - if (c.ignoreCase == null) { + var ignoreCase = c.ignoreCase; + if (ignoreCase == null) { _testIgnorePath(c, path, expected, false); _testIgnorePath(c, path, expected, true); } else { - _testIgnorePath(c, path, expected, c.ignoreCase); + _testIgnorePath(c, path, expected, ignoreCase); } }); } @@ -200,7 +200,7 @@ final bool skipOnWindows; /// Test with `core.ignoreCase` set to `true`, `false` or both (if `null`). - final bool ignoreCase; + final bool? ignoreCase; TestData( this.name, @@ -977,6 +977,13 @@ 'folder/a.txt': true, }), + TestData('folder/* does not ignore `folder` itself', { + '.': ['folder/*', '!folder/a.txt'], + }, { + 'folder/a.txt': false, + 'folder/b.txt': true, + }), + // Case sensitivity TestData( 'simple',
diff --git a/test/io_test.dart b/test/io_test.dart index b54bc91..2c529cd 100644 --- a/test/io_test.dart +++ b/test/io_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -463,14 +461,14 @@ } void testExistencePredicate(String name, bool Function(String path) predicate, - {bool forFile, - bool forFileSymlink, - bool forMultiLevelFileSymlink, - bool forDirectory, - bool forDirectorySymlink, - bool forMultiLevelDirectorySymlink, - bool forBrokenSymlink, - bool forMultiLevelBrokenSymlink}) { + {required bool forFile, + required bool forFileSymlink, + required bool forMultiLevelFileSymlink, + required bool forDirectory, + required bool forDirectorySymlink, + required bool forMultiLevelDirectorySymlink, + required bool forBrokenSymlink, + required bool forMultiLevelBrokenSymlink}) { group(name, () { test('returns $forFile for a file', () { expect(withTempDir((temp) {
diff --git a/test/levenshtein_test.dart b/test/levenshtein_test.dart index 6d113c7..67361af 100644 --- a/test/levenshtein_test.dart +++ b/test/levenshtein_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/levenshtein.dart'; import 'package:test/test.dart';
diff --git a/test/lish/archives_and_uploads_a_package_test.dart b/test/lish/archives_and_uploads_a_package_test.dart index 2efeb4a..88e4862 100644 --- a/test/lish/archives_and_uploads_a_package_test.dart +++ b/test/lish/archives_and_uploads_a_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:path/path.dart' as p; @@ -21,14 +19,44 @@ test('archives and uploads a package', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { + return shelf.Response.ok(jsonEncode({ + 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} + })); + }); + + expect(pub.stdout, emits(startsWith('Uploading...'))); + expect(pub.stdout, emits('Package test_pkg 1.0.0 uploaded!')); + await pub.shouldExit(exit_codes.SUCCESS); + }); + + test('publishes to hosted-url with path', () async { + await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': globalServer.url + '/sub/folder', 'env': 'TOKEN'}, + ] + }).create(); + var pub = await startPublish( + globalServer, + path: '/sub/folder', + authMethod: 'token', + environment: {'TOKEN': 'access token'}, + ); + + await confirmPublish(pub); + handleUploadForm(globalServer, path: '/sub/folder'); + handleUpload(globalServer); + + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} })); @@ -55,14 +83,14 @@ await d.dir(p.join(appPath, 'empty')).create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart index f2e542f..0f792d5 100644 --- a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart +++ b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -16,13 +14,13 @@ test("cloud storage upload doesn't redirect", () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); + handleUploadForm(globalServer); - globalPackageServer.expect('POST', '/upload', (request) async { + globalServer.expect('POST', '/upload', (request) async { await request.read().drain(); return shelf.Response(200); });
diff --git a/test/lish/cloud_storage_upload_provides_an_error_test.dart b/test/lish/cloud_storage_upload_provides_an_error_test.dart index a67d85b..5dec03d 100644 --- a/test/lish/cloud_storage_upload_provides_an_error_test.dart +++ b/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -16,13 +14,13 @@ test('cloud storage upload provides an error', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); + handleUploadForm(globalServer); - globalPackageServer.expect('POST', '/upload', (request) { + globalServer.expect('POST', '/upload', (request) { return request.read().drain().then((_) { return shelf.Response.notFound( '<Error><Message>Your request sucked.</Message></Error>',
diff --git a/test/lish/does_not_include_dot_file.dart b/test/lish/does_not_include_dot_file.dart index 6dfa622..cec8ab0 100644 --- a/test/lish/does_not_include_dot_file.dart +++ b/test/lish/does_not_include_dot_file.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -32,14 +30,14 @@ test('Check if package doesn\'t include dot-files', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/does_not_publish_if_private_test.dart b/test/lish/does_not_publish_if_private_test.dart index 9ab8712..52321c2 100644 --- a/test/lish/does_not_publish_if_private_test.dart +++ b/test/lish/does_not_publish_if_private_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/does_not_publish_if_private_with_server_arg_test.dart b/test/lish/does_not_publish_if_private_with_server_arg_test.dart index c33b1a3..689609b 100644 --- a/test/lish/does_not_publish_if_private_with_server_arg_test.dart +++ b/test/lish/does_not_publish_if_private_with_server_arg_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/dot_folder_name_test.dart b/test/lish/dot_folder_name_test.dart new file mode 100644 index 0000000..9f64839 --- /dev/null +++ b/test/lish/dot_folder_name_test.dart
@@ -0,0 +1,28 @@ +// 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 'package:pub/src/exit_codes.dart' as exit_codes; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + test('Can publish files in a .folder', () async { + await d.git(appPath).create(); + await d.validPackage.create(); + await d.dir(appPath, [ + d.dir('.vscode', [d.file('a')]), + d.file('.pubignore', '!.vscode/') + ]).create(); + + await runPub( + args: ['lish', '--dry-run'], + output: contains(''' +|-- .vscode +| '-- a'''), + exitCode: exit_codes.SUCCESS, + ); + }); +}
diff --git a/test/lish/dry_run_warns_about_server_checks.dart b/test/lish/dry_run_warns_about_server_checks.dart index 8e12f9b..ad7abe0 100644 --- a/test/lish/dry_run_warns_about_server_checks.dart +++ b/test/lish/dry_run_warns_about_server_checks.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/test/lish/force_cannot_be_combined_with_dry_run_test.dart index def3f7a..9d2233c 100644 --- a/test/lish/force_cannot_be_combined_with_dry_run_test.dart +++ b/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -14,17 +12,10 @@ setUp(d.validPackage.create); test('--force cannot be combined with --dry-run', () async { - await runPub(args: ['lish', '--force', '--dry-run'], error: ''' -Cannot use both --force and --dry-run. - -Usage: pub publish [options] --h, --help Print this usage information. --n, --dry-run Validate but do not publish the package. --f, --force Publish without confirmation if there are no errors. --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation. -''', exitCode: exit_codes.USAGE); + await runPub( + args: ['lish', '--force', '--dry-run'], + error: contains('Cannot use both --force and --dry-run.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/lish/force_does_not_publish_if_private_test.dart b/test/lish/force_does_not_publish_if_private_test.dart index 9ca4bf6..0d4ad59 100644 --- a/test/lish/force_does_not_publish_if_private_test.dart +++ b/test/lish/force_does_not_publish_if_private_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/force_does_not_publish_if_there_are_errors_test.dart b/test/lish/force_does_not_publish_if_there_are_errors_test.dart index 26978ad..481f627 100644 --- a/test/lish/force_does_not_publish_if_there_are_errors_test.dart +++ b/test/lish/force_does_not_publish_if_there_are_errors_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -23,7 +21,7 @@ ]).create(); await servePackages(); - var pub = await startPublish(globalPackageServer, args: ['--force']); + var pub = await startPublish(globalServer, args: ['--force']); await pub.shouldExit(exit_codes.DATA); expect(
diff --git a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart index 59c8233..c5d8957 100644 --- a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart +++ b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -19,13 +17,13 @@ test('--force publishes if there are no warnings or errors', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer, args: ['--force']); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer, args: ['--force']); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/force_publishes_if_there_are_warnings_test.dart b/test/lish/force_publishes_if_there_are_warnings_test.dart index c217b29..9fb3d53 100644 --- a/test/lish/force_publishes_if_there_are_warnings_test.dart +++ b/test/lish/force_publishes_if_there_are_warnings_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -24,13 +22,13 @@ await d.dir(appPath, [d.pubspec(pkg)]).create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer, args: ['--force']); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer, args: ['--force']); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/many_files_test.dart b/test/lish/many_files_test.dart index 02db6b2..36f4ed7 100644 --- a/test/lish/many_files_test.dart +++ b/test/lish/many_files_test.dart
@@ -2,11 +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. -// @dart=2.10 - import 'dart:convert'; import 'dart:io'; -import 'dart:math' as math; import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -38,7 +35,7 @@ int argMax; if (Platform.isWindows) { // On Windows, the maximum argument list length is 8^5 bytes. - argMax = math.pow(8, 5); + argMax = 32768; // 8^5 } else { // On POSIX, the maximum argument list length can be retrieved // automatically. @@ -76,14 +73,14 @@ } await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/package_creation_provides_a_malformed_error_test.dart b/test/lish/package_creation_provides_a_malformed_error_test.dart index d78e495..7ab0bcd 100644 --- a/test/lish/package_creation_provides_a_malformed_error_test.dart +++ b/test/lish/package_creation_provides_a_malformed_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -18,15 +16,15 @@ test('package creation provides a malformed error', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); var body = {'error': 'Your package was too boring.'}; - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.notFound(jsonEncode(body)); });
diff --git a/test/lish/package_creation_provides_a_malformed_success_test.dart b/test/lish/package_creation_provides_a_malformed_success_test.dart index 67c10ef..089d09e 100644 --- a/test/lish/package_creation_provides_a_malformed_success_test.dart +++ b/test/lish/package_creation_provides_a_malformed_success_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -18,15 +16,15 @@ test('package creation provides a malformed success', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); var body = {'success': 'Your package was awesome.'}; - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode(body)); });
diff --git a/test/lish/package_creation_provides_an_error_test.dart b/test/lish/package_creation_provides_an_error_test.dart index 49166c1..f5ff128 100644 --- a/test/lish/package_creation_provides_an_error_test.dart +++ b/test/lish/package_creation_provides_an_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -18,14 +16,14 @@ test('package creation provides an error', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.notFound(jsonEncode({ 'error': {'message': 'Your package was too boring.'} }));
diff --git a/test/lish/package_creation_provides_invalid_json_test.dart b/test/lish/package_creation_provides_invalid_json_test.dart index 8cdfd5b..2cd6212 100644 --- a/test/lish/package_creation_provides_invalid_json_test.dart +++ b/test/lish/package_creation_provides_invalid_json_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -16,14 +14,14 @@ test('package creation provides invalid JSON', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok('{not json'); });
diff --git a/test/lish/package_validation_has_a_warning_and_continues_test.dart b/test/lish/package_validation_has_a_warning_and_continues_test.dart index ec55be9..c39dbc4 100644 --- a/test/lish/package_validation_has_a_warning_and_continues_test.dart +++ b/test/lish/package_validation_has_a_warning_and_continues_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:pub/src/exit_codes.dart' as exit_codes; @@ -24,13 +22,13 @@ await d.dir(appPath, [d.pubspec(pkg)]).create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); pub.stdin.writeln('y'); - handleUploadForm(globalPackageServer); - handleUpload(globalPackageServer); + handleUploadForm(globalServer); + handleUpload(globalServer); - globalPackageServer.expect('GET', '/create', (request) { + globalServer.expect('GET', '/create', (request) { return shelf.Response.ok(jsonEncode({ 'success': {'message': 'Package test_pkg 1.0.0 uploaded!'} }));
diff --git a/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart b/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart index fbdacc4..0d5a563 100644 --- a/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart +++ b/test/lish/package_validation_has_a_warning_and_is_canceled_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -20,7 +18,7 @@ await d.dir(appPath, [d.pubspec(pkg)]).create(); await servePackages(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); pub.stdin.writeln('n'); await pub.shouldExit(exit_codes.DATA);
diff --git a/test/lish/package_validation_has_an_error_test.dart b/test/lish/package_validation_has_an_error_test.dart index 9fab3a5..14c83c0 100644 --- a/test/lish/package_validation_has_an_error_test.dart +++ b/test/lish/package_validation_has_an_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -23,7 +21,7 @@ ]).create(); await servePackages(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); await pub.shouldExit(exit_codes.DATA); expect(
diff --git a/test/lish/preview_errors_if_private_test.dart b/test/lish/preview_errors_if_private_test.dart index c816c6e..fb7160a 100644 --- a/test/lish/preview_errors_if_private_test.dart +++ b/test/lish/preview_errors_if_private_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/preview_package_validation_has_a_warning_test.dart b/test/lish/preview_package_validation_has_a_warning_test.dart index c3aa01d..69f59af 100644 --- a/test/lish/preview_package_validation_has_a_warning_test.dart +++ b/test/lish/preview_package_validation_has_a_warning_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -21,7 +19,7 @@ await d.dir(appPath, [d.pubspec(pkg)]).create(); await servePackages(); - var pub = await startPublish(globalPackageServer, args: ['--dry-run']); + var pub = await startPublish(globalServer, args: ['--dry-run']); await pub.shouldExit(exit_codes.DATA); expect(
diff --git a/test/lish/preview_package_validation_has_no_warnings_test.dart b/test/lish/preview_package_validation_has_no_warnings_test.dart index 586708c..179c648 100644 --- a/test/lish/preview_package_validation_has_no_warnings_test.dart +++ b/test/lish/preview_package_validation_has_no_warnings_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -19,8 +17,8 @@ packageMap('test_pkg', '1.0.0', null, null, {'sdk': '>=1.8.0 <2.0.0'}); await d.dir(appPath, [d.pubspec(pkg)]).create(); - await servePackages((_) {}); - var pub = await startPublish(globalPackageServer, args: ['--dry-run']); + await servePackages(); + var pub = await startPublish(globalServer, args: ['--dry-run']); await pub.shouldExit(exit_codes.SUCCESS); expect(pub.stderr, emitsThrough('Package has 0 warnings.'));
diff --git a/test/lish/server_arg_does_not_override_private_test.dart b/test/lish/server_arg_does_not_override_private_test.dart index baba7d6..58a1af1 100644 --- a/test/lish/server_arg_does_not_override_private_test.dart +++ b/test/lish/server_arg_does_not_override_private_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/server_arg_overrides_publish_to_url_test.dart b/test/lish/server_arg_overrides_publish_to_url_test.dart index 508c0b3..1597146 100644 --- a/test/lish/server_arg_overrides_publish_to_url_test.dart +++ b/test/lish/server_arg_overrides_publish_to_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -15,16 +13,15 @@ test('an explicit --server argument overrides a "publish_to" url', () async { // Create a real server that can reject requests because validators will // try to ping it, and will use multiple retries when doing so. - final packageServer = await DescriptorServer.start(); - final fakePackageServer = 'http://localhost:${packageServer.port}'; + final packageServer = await startPackageServer(); var pkg = packageMap('test_pkg', '1.0.0'); pkg['publish_to'] = 'http://pubspec.com'; await d.dir(appPath, [d.pubspec(pkg)]).create(); await runPub( - args: ['lish', '--dry-run', '--server', fakePackageServer], - output: contains(fakePackageServer), + args: ['lish', '--dry-run', '--server', packageServer.url], + output: contains(packageServer.url), exitCode: exit_codes.DATA); await packageServer.close();
diff --git a/test/lish/upload_form_fields_has_a_non_string_value_test.dart b/test/lish/upload_form_fields_has_a_non_string_value_test.dart index 3ecb2fb..78a54fa 100644 --- a/test/lish/upload_form_fields_has_a_non_string_value_test.dart +++ b/test/lish/upload_form_fields_has_a_non_string_value_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -16,9 +14,9 @@ setUp(d.validPackage.create); test('upload form fields has a non-string value', () async { - await servePackages((_) {}); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await servePackages(); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); @@ -26,7 +24,7 @@ 'url': 'http://example.com/upload', 'fields': {'field': 12} }; - handleUploadForm(globalPackageServer, body); + handleUploadForm(globalServer, body: body); expect(pub.stderr, emits('Invalid server response:')); expect(pub.stderr, emits(jsonEncode(body))); await pub.shouldExit(1);
diff --git a/test/lish/upload_form_fields_is_not_a_map_test.dart b/test/lish/upload_form_fields_is_not_a_map_test.dart index fed0f38..d18c1ee 100644 --- a/test/lish/upload_form_fields_is_not_a_map_test.dart +++ b/test/lish/upload_form_fields_is_not_a_map_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -17,13 +15,13 @@ test('upload form fields is not a map', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); var body = {'url': 'http://example.com/upload', 'fields': 12}; - handleUploadForm(globalPackageServer, body); + handleUploadForm(globalServer, body: body); expect(pub.stderr, emits('Invalid server response:')); expect(pub.stderr, emits(jsonEncode(body))); await pub.shouldExit(1);
diff --git a/test/lish/upload_form_is_missing_fields_test.dart b/test/lish/upload_form_is_missing_fields_test.dart index a49b0d6..b0032f8 100644 --- a/test/lish/upload_form_is_missing_fields_test.dart +++ b/test/lish/upload_form_is_missing_fields_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -17,13 +15,13 @@ test('upload form is missing fields', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); var body = {'url': 'http://example.com/upload'}; - handleUploadForm(globalPackageServer, body); + handleUploadForm(globalServer, body: body); expect(pub.stderr, emits('Invalid server response:')); expect(pub.stderr, emits(jsonEncode(body))); await pub.shouldExit(1);
diff --git a/test/lish/upload_form_is_missing_url_test.dart b/test/lish/upload_form_is_missing_url_test.dart index 50f5fa5..eae43ea 100644 --- a/test/lish/upload_form_is_missing_url_test.dart +++ b/test/lish/upload_form_is_missing_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -17,8 +15,8 @@ test('upload form is missing url', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); @@ -26,7 +24,7 @@ 'fields': {'field1': 'value1', 'field2': 'value2'} }; - handleUploadForm(globalPackageServer, body); + handleUploadForm(globalServer, body: body); expect(pub.stderr, emits('Invalid server response:')); expect(pub.stderr, emits(jsonEncode(body))); await pub.shouldExit(1);
diff --git a/test/lish/upload_form_provides_an_error_test.dart b/test/lish/upload_form_provides_an_error_test.dart index c5fd41e..35932b8 100644 --- a/test/lish/upload_form_provides_an_error_test.dart +++ b/test/lish/upload_form_provides_an_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -16,15 +14,13 @@ setUp(d.validPackage.create); test('upload form provides an error', () async { - await servePackages((_) {}); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await servePackages(); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - globalPackageServer.extraHandlers['/api/packages/versions/new'] = - expectAsync1((request) { - expect(request.method, 'GET'); + globalServer.expect('GET', '/api/packages/versions/new', (request) async { return shelf.Response.notFound(jsonEncode({ 'error': {'message': 'your request sucked'} }));
diff --git a/test/lish/upload_form_provides_invalid_json_test.dart b/test/lish/upload_form_provides_invalid_json_test.dart index a4fa5d7..a046755 100644 --- a/test/lish/upload_form_provides_invalid_json_test.dart +++ b/test/lish/upload_form_provides_invalid_json_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -15,12 +13,12 @@ test('upload form provides invalid JSON', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - globalPackageServer.expect('GET', '/api/packages/versions/new', + globalServer.expect('GET', '/api/packages/versions/new', (request) => shelf.Response.ok('{not json')); expect(
diff --git a/test/lish/upload_form_url_is_not_a_string_test.dart b/test/lish/upload_form_url_is_not_a_string_test.dart index 99909a4..f69fd1f 100644 --- a/test/lish/upload_form_url_is_not_a_string_test.dart +++ b/test/lish/upload_form_url_is_not_a_string_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -17,8 +15,8 @@ test('upload form url is not a string', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); @@ -27,7 +25,7 @@ 'fields': {'field1': 'value1', 'field2': 'value2'} }; - handleUploadForm(globalPackageServer, body); + handleUploadForm(globalServer, body: body); expect(pub.stderr, emits('Invalid server response:')); expect(pub.stderr, emits(jsonEncode(body))); await pub.shouldExit(1);
diff --git a/test/lish/uses_publish_to_url_test.dart b/test/lish/uses_publish_to_url_test.dart index e7f9cf3..47496f7 100644 --- a/test/lish/uses_publish_to_url_test.dart +++ b/test/lish/uses_publish_to_url_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/lish/utils.dart b/test/lish/utils.dart index 5f18444..f134e4a 100644 --- a/test/lish/utils.dart +++ b/test/lish/utils.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -11,8 +9,8 @@ import '../test_pub.dart'; -void handleUploadForm(PackageServer server, [Map body]) { - server.expect('GET', '/api/packages/versions/new', (request) { +void handleUploadForm(PackageServer server, {Map? body, String path = ''}) { + server.expect('GET', '$path/api/packages/versions/new', (request) { expect( request.headers, containsPair('authorization', 'Bearer access token'));
diff --git a/test/list_package_dirs/ignores_updated_pubspec_test.dart b/test/list_package_dirs/ignores_updated_pubspec_test.dart index edec570..2524681 100644 --- a/test/list_package_dirs/ignores_updated_pubspec_test.dart +++ b/test/list_package_dirs/ignores_updated_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart';
diff --git a/test/list_package_dirs/includes_dev_dependencies_test.dart b/test/list_package_dirs/includes_dev_dependencies_test.dart index 10f4f56..61cc56b 100644 --- a/test/list_package_dirs/includes_dev_dependencies_test.dart +++ b/test/list_package_dirs/includes_dev_dependencies_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart';
diff --git a/test/list_package_dirs/lists_dependency_directories_test.dart b/test/list_package_dirs/lists_dependency_directories_test.dart index 5d5b982..2cd9664 100644 --- a/test/list_package_dirs/lists_dependency_directories_test.dart +++ b/test/list_package_dirs/lists_dependency_directories_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; @@ -14,7 +12,8 @@ void main() { test('prints the local paths to all packages in the lockfile', () async { - await servePackages((builder) => builder.serve('bar', '1.0.0')); + final server = await servePackages() + ..serve('bar', '1.0.0'); await d .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create(); @@ -39,7 +38,7 @@ 'packages': { 'foo': path.join(d.sandbox, 'foo', 'lib'), 'bar': path.join(d.sandbox, cachePath, 'hosted', - 'localhost%58${globalServer.port}', 'bar-1.0.0', 'lib'), + 'localhost%58${server.port}', 'bar-1.0.0', 'lib'), 'myapp': canonicalize(path.join(d.sandbox, appPath, 'lib')) }, 'input_files': [
diff --git a/test/list_package_dirs/lockfile_error_test.dart b/test/list_package_dirs/lockfile_error_test.dart index 16860f4..f4440ec 100644 --- a/test/list_package_dirs/lockfile_error_test.dart +++ b/test/list_package_dirs/lockfile_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart';
diff --git a/test/list_package_dirs/missing_pubspec_test.dart b/test/list_package_dirs/missing_pubspec_test.dart index d3c61de..83a58c2 100644 --- a/test/list_package_dirs/missing_pubspec_test.dart +++ b/test/list_package_dirs/missing_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart';
diff --git a/test/list_package_dirs/no_lockfile_test.dart b/test/list_package_dirs/no_lockfile_test.dart index 9e1078b..5939099 100644 --- a/test/list_package_dirs/no_lockfile_test.dart +++ b/test/list_package_dirs/no_lockfile_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/list_package_dirs/pubspec_error_test.dart b/test/list_package_dirs/pubspec_error_test.dart index 321e555..c282c5c 100644 --- a/test/list_package_dirs/pubspec_error_test.dart +++ b/test/list_package_dirs/pubspec_error_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart';
diff --git a/test/lock_file_test.dart b/test/lock_file_test.dart index 18edc94..4360c7c 100644 --- a/test/lock_file_test.dart +++ b/test/lock_file_test.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:pub/src/language_version.dart'; import 'package:pub/src/lock_file.dart'; import 'package:pub/src/package_name.dart'; import 'package:pub/src/source.dart'; @@ -22,14 +21,15 @@ throw UnsupportedError('Cannot download fake packages.'); @override - PackageRef parseRef(String name, description, {String containingPath}) { + PackageRef parseRef(String name, description, + {String? containingPath, LanguageVersion? languageVersion}) { if (!description.endsWith(' desc')) throw FormatException('Bad'); return PackageRef(name, this, description); } @override PackageId parseId(String name, Version version, description, - {String containingPath}) { + {String? containingPath}) { if (!description.endsWith(' desc')) throw FormatException('Bad'); return PackageId(name, this, version, description); } @@ -79,13 +79,13 @@ expect(lockFile.packages.length, equals(2)); - var bar = lockFile.packages['bar']; + var bar = lockFile.packages['bar']!; expect(bar.name, equals('bar')); expect(bar.version, equals(Version(1, 2, 3))); expect(bar.source, equals(fakeSource)); expect(bar.description, equals('bar desc')); - var foo = lockFile.packages['foo']; + var foo = lockFile.packages['foo']!; expect(foo.name, equals('foo')); expect(foo.version, equals(Version(2, 3, 4))); expect(foo.source, equals(fakeSource)); @@ -100,7 +100,7 @@ version: 1.2.3 description: foo desc ''', sources); - var foo = lockFile.packages['foo']; + var foo = lockFile.packages['foo']!; expect(foo.source, equals(sources['bad'])); }); @@ -261,7 +261,7 @@ }); expect( - loadYaml(lockfile.serialize(null)), + loadYaml(lockfile.serialize('')), equals({ 'sdks': {'dart': 'any'}, 'packages': {
diff --git a/test/must_pub_get_test.dart b/test/must_pub_get_test.dart index edea182..71d9c16 100644 --- a/test/must_pub_get_test.dart +++ b/test/must_pub_get_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -16,12 +14,14 @@ import 'descriptor.dart' as d; import 'test_pub.dart'; +late PackageServer server; + void main() { setUp(() async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - }); + server = await servePackages(); + + server.serve('foo', '1.0.0'); + server.serve('foo', '2.0.0'); await d.dir(appPath, [ d.appPubspec(), @@ -213,7 +213,7 @@ d.appPubspec({'foo': '1.0.0'}) ]).create(); - await pubGet(); + await pubGet(args: ['--legacy-packages-file']); deleteEntry(p.join(d.sandbox, cachePath)); @@ -235,7 +235,7 @@ }) ]).create(); - await pubGet(); + await pubGet(args: ['--legacy-packages-file']); await createPackagesFile(appPath); @@ -257,7 +257,7 @@ }) ]).create(); - await pubGet(); + await pubGet(args: ['--legacy-packages-file']); await d.dir(appPath, [ d.file('.packages', ''' @@ -284,7 +284,7 @@ }) ]).create(); - await pubGet(); + await pubGet(args: ['--legacy-packages-file']); await createPackagesFile(appPath, dependenciesInSandBox: ['foo']); @@ -334,10 +334,8 @@ setUp(() async { // Avoid using a path dependency because it triggers the full validation // logic. We want to be sure SDK-validation works without that logic. - globalPackageServer.add((builder) { - builder.serve('foo', '3.0.0', pubspec: { - 'environment': {'sdk': '>=1.0.0 <2.0.0'} - }); + server.serve('foo', '3.0.0', pubspec: { + 'environment': {'sdk': '>=1.0.0 <2.0.0'} }); await d.dir(appPath, [ @@ -362,10 +360,8 @@ 'current Flutter SDK', () async { // Avoid using a path dependency because it triggers the full validation // logic. We want to be sure SDK-validation works without that logic. - globalPackageServer.add((builder) { - builder.serve('foo', '3.0.0', pubspec: { - 'environment': {'flutter': '>=1.0.0 <2.0.0'} - }); + server.serve('foo', '3.0.0', pubspec: { + 'environment': {'flutter': '>=1.0.0 <2.0.0'} }); await d.dir('flutter', [d.file('version', '1.2.3')]).create(); @@ -456,7 +452,7 @@ group("doesn't require the user to run pub get first if", () { group( 'the pubspec is older than the lockfile which is older than the ' - 'packages file, even if the contents are wrong', () { + 'package-config, even if the contents are wrong', () { setUp(() async { await d.dir(appPath, [ d.appPubspec({'foo': '1.0.0'}) @@ -465,7 +461,6 @@ await _touch('pubspec.yaml'); await _touch('pubspec.lock'); - await _touch('.packages'); await _touch('.dart_tool/package_config.json'); }); @@ -524,10 +519,8 @@ group("an overridden dependency's SDK constraint is unmatched", () { setUp(() async { - globalPackageServer.add((builder) { - builder.serve('bar', '1.0.0', pubspec: { - 'environment': {'sdk': '0.0.0-fake'} - }); + server.serve('bar', '1.0.0', pubspec: { + 'environment': {'sdk': '0.0.0-fake'} }); await d.dir(appPath, [ @@ -549,10 +542,8 @@ () async { // Avoid using a path dependency because it triggers the full validation // logic. We want to be sure SDK-validation works without that logic. - globalPackageServer.add((builder) { - builder.serve('foo', '3.0.0', pubspec: { - 'environment': {'flutter': '>=1.0.0 <2.0.0'} - }); + server.serve('foo', '3.0.0', pubspec: { + 'environment': {'flutter': '>=1.0.0 <2.0.0'} }); await d.dir('flutter', [d.file('version', '1.2.3')]).create(); @@ -608,14 +599,11 @@ File(p.join(d.sandbox, 'myapp/pubspec.yaml')).lastModifiedSync(); var lockFileModified = File(p.join(d.sandbox, 'myapp/pubspec.lock')).lastModifiedSync(); - var packagesModified = - File(p.join(d.sandbox, 'myapp/.packages')).lastModifiedSync(); var packageConfigModified = File(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json')) .lastModifiedSync(); expect(!pubspecModified.isAfter(lockFileModified), isTrue); - expect(!lockFileModified.isAfter(packagesModified), isTrue); expect(!lockFileModified.isAfter(packageConfigModified), isTrue); }); }
diff --git a/test/no_packages_dir_test.dart b/test/no_packages_dir_test.dart index cdd6351..3a88bc5 100644 --- a/test/no_packages_dir_test.dart +++ b/test/no_packages_dir_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import 'descriptor.dart' as d;
diff --git a/test/oauth2/logout_test.dart b/test/oauth2/logout_test.dart index 81d4125..a12a652 100644 --- a/test/oauth2/logout_test.dart +++ b/test/oauth2/logout_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -13,7 +11,7 @@ test('with an existing credentials file, deletes it.', () async { await servePackages(); await d - .credentialsFile(globalPackageServer, 'access token', + .credentialsFile(globalServer, 'access token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1))) .create(); @@ -30,7 +28,7 @@ await servePackages(); await d .credentialsFile( - globalPackageServer, + globalServer, 'access token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1)), @@ -39,7 +37,7 @@ await d .legacyCredentialsFile( - globalPackageServer, + globalServer, 'access token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1)),
diff --git a/test/oauth2/utils.dart b/test/oauth2/utils.dart index b7d765e..dab8c92 100644 --- a/test/oauth2/utils.dart +++ b/test/oauth2/utils.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -24,10 +22,10 @@ var line = await pub.stdout.next; var match = - RegExp(r'[?&]redirect_uri=([0-9a-zA-Z.%+-]+)[$&]').firstMatch(line); + RegExp(r'[?&]redirect_uri=([0-9a-zA-Z.%+-]+)[$&]').firstMatch(line)!; expect(match, isNotNull); - var redirectUrl = Uri.parse(Uri.decodeComponent(match.group(1))); + var redirectUrl = Uri.parse(Uri.decodeComponent(match.group(1)!)); redirectUrl = _addQueryParameters(redirectUrl, {'code': 'access code'}); // Expect the /token request @@ -61,8 +59,8 @@ } /// Convert a [Map] from parameter names to values to a URL query string. -String _mapToQuery(Map<String, String> map) { - var pairs = <List<String>>[]; +String _mapToQuery(Map<String, String?> map) { + var pairs = <List<String?>>[]; map.forEach((key, value) { key = Uri.encodeQueryComponent(key); value = (value == null || value.isEmpty)
diff --git a/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart b/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart index 5585526..75b47ab 100644 --- a/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart +++ b/test/oauth2/with_a_malformed_credentials_authenticates_again_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -21,11 +19,11 @@ await d.dir( configPath, [d.file('pub-credentials.json', '{bad json')]).create(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); await confirmPublish(pub); - await authorizePub(pub, globalPackageServer, 'new access token'); + await authorizePub(pub, globalServer, 'new access token'); - globalPackageServer.expect('GET', '/api/packages/versions/new', (request) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { expect(request.headers, containsPair('authorization', 'Bearer new access token')); @@ -36,6 +34,6 @@ // do so rather than killing it so it'll write out the credentials file. await pub.shouldExit(1); - await d.credentialsFile(globalPackageServer, 'new access token').validate(); + await d.credentialsFile(globalServer, 'new access token').validate(); }); }
diff --git a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart index ad6559f..3c22994 100644 --- a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart +++ b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -14,8 +12,8 @@ await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart index 3354bbc..624f427 100644 --- a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart +++ b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -23,14 +21,14 @@ await servePackages(); await d - .credentialsFile(globalPackageServer, 'access token', + .credentialsFile(globalServer, 'access token', refreshToken: 'bad refresh token', expiration: DateTime.now().subtract(Duration(hours: 1))) .create(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); - globalPackageServer.expect('POST', '/token', (request) { + globalServer.expect('POST', '/token', (request) { return request.read().drain().then((_) { return shelf.Response(400, body: jsonEncode({'error': 'invalid_request'}), @@ -41,11 +39,10 @@ await confirmPublish(pub); await expectLater(pub.stdout, emits(startsWith('Uploading...'))); - await authorizePub(pub, globalPackageServer, 'new access token'); + await authorizePub(pub, globalServer, 'new access token'); var done = Completer(); - globalPackageServer.expect('GET', '/api/packages/versions/new', - (request) async { + globalServer.expect('GET', '/api/packages/versions/new', (request) async { expect(request.headers, containsPair('authorization', 'Bearer new access token'));
diff --git a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart index 16062a7..7fbbb9f 100644 --- a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart +++ b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -20,15 +18,15 @@ await servePackages(); await d - .credentialsFile(globalPackageServer, 'access token', + .credentialsFile(globalServer, 'access token', refreshToken: 'refresh token', expiration: DateTime.now().subtract(Duration(hours: 1))) .create(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); await confirmPublish(pub); - globalPackageServer.expect('POST', '/token', (request) { + globalServer.expect('POST', '/token', (request) { return request.readAsString().then((body) { expect( body, matches(RegExp(r'(^|&)refresh_token=refresh\+token(&|$)'))); @@ -40,7 +38,7 @@ }); }); - globalPackageServer.expect('GET', '/api/packages/versions/new', (request) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { expect(request.headers, containsPair('authorization', 'Bearer new access token')); @@ -50,7 +48,7 @@ await pub.shouldExit(); await d - .credentialsFile(globalPackageServer, 'new access token', + .credentialsFile(globalServer, 'new access token', refreshToken: 'refresh token') .validate(); });
diff --git a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart index 6437a5c..803c529 100644 --- a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart +++ b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -19,20 +17,20 @@ await servePackages(); await d - .credentialsFile(globalPackageServer, 'access token', + .credentialsFile(globalServer, 'access token', expiration: DateTime.now().subtract(Duration(hours: 1))) .create(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); await confirmPublish(pub); await expectLater( pub.stderr, emits("Pub's authorization to upload packages has expired and " "can't be automatically refreshed.")); - await authorizePub(pub, globalPackageServer, 'new access token'); + await authorizePub(pub, globalServer, 'new access token'); - globalPackageServer.expect('GET', '/api/packages/versions/new', (request) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { expect(request.headers, containsPair('authorization', 'Bearer new access token')); @@ -43,6 +41,6 @@ // do so rather than killing it so it'll write out the credentials file. await pub.shouldExit(1); - await d.credentialsFile(globalPackageServer, 'new access token').validate(); + await d.credentialsFile(globalServer, 'new access token').validate(); }); }
diff --git a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart index 2106960..961a465 100644 --- a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart +++ b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:shelf/shelf.dart' as shelf; import 'package:test/test.dart'; @@ -18,11 +16,11 @@ await d.validPackage.create(); await servePackages(); - var pub = await startPublish(globalPackageServer); + var pub = await startPublish(globalServer); await confirmPublish(pub); - await authorizePub(pub, globalPackageServer); + await authorizePub(pub, globalServer); - globalPackageServer.expect('GET', '/api/packages/versions/new', (request) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { expect(request.headers, containsPair('authorization', 'Bearer access token')); @@ -33,6 +31,6 @@ // do so rather than killing it so it'll write out the credentials file. await pub.shouldExit(1); - await d.credentialsFile(globalPackageServer, 'access token').validate(); + await d.credentialsFile(globalServer, 'access token').validate(); }); }
diff --git a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart index 9ef5e69..2e3b62f 100644 --- a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart +++ b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:shelf/shelf.dart' as shelf; @@ -18,12 +16,12 @@ 'credentials.json', () async { await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPublish(globalPackageServer); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPublish(globalServer); await confirmPublish(pub); - globalPackageServer.expect('GET', '/api/packages/versions/new', (request) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { return shelf.Response(401, body: jsonEncode({ 'error': {'message': 'your token sucks'}
diff --git a/test/outdated/goldens/bad_arguments.txt b/test/outdated/goldens/bad_arguments.txt deleted file mode 100644 index b184530..0000000 --- a/test/outdated/goldens/bad_arguments.txt +++ /dev/null
@@ -1,58 +0,0 @@ -$ pub outdated random_argument -[ERR] Command "outdated" does not take any arguments. -[ERR] -[ERR] Usage: pub outdated [options] -[ERR] -h, --help Print this usage information. -[ERR] --[no-]color Whether to color the output. -[ERR] Defaults to color when connected to a -[ERR] terminal, and no-color otherwise. -[ERR] --[no-]dependency-overrides Show resolutions with `dependency_overrides`. -[ERR] (defaults to on) -[ERR] --[no-]dev-dependencies Take dev dependencies into account. -[ERR] (defaults to on) -[ERR] --json Output the results using a json format. -[ERR] --mode=<PROPERTY> Highlight versions with PROPERTY. -[ERR] Only packages currently missing that PROPERTY -[ERR] will be included unless --show-all. -[ERR] [outdated (default), null-safety] -[ERR] --[no-]prereleases Include prereleases in latest version. -[ERR] (defaults to on in --mode=null-safety). -[ERR] --[no-]show-all Include dependencies that are already -[ERR] fullfilling --mode. -[ERR] --[no-]transitive Show transitive dependencies. -[ERR] (defaults to off in --mode=null-safety). -[ERR] -C, --directory=<dir> Run this in the directory<dir>. -[ERR] -[ERR] Run "pub help" to see global options. -[ERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation. -[Exit code] 64 - -$ pub outdated --bad_flag -[ERR] Could not find an option named "bad_flag". -[ERR] -[ERR] Usage: pub outdated [options] -[ERR] -h, --help Print this usage information. -[ERR] --[no-]color Whether to color the output. -[ERR] Defaults to color when connected to a -[ERR] terminal, and no-color otherwise. -[ERR] --[no-]dependency-overrides Show resolutions with `dependency_overrides`. -[ERR] (defaults to on) -[ERR] --[no-]dev-dependencies Take dev dependencies into account. -[ERR] (defaults to on) -[ERR] --json Output the results using a json format. -[ERR] --mode=<PROPERTY> Highlight versions with PROPERTY. -[ERR] Only packages currently missing that PROPERTY -[ERR] will be included unless --show-all. -[ERR] [outdated (default), null-safety] -[ERR] --[no-]prereleases Include prereleases in latest version. -[ERR] (defaults to on in --mode=null-safety). -[ERR] --[no-]show-all Include dependencies that are already -[ERR] fullfilling --mode. -[ERR] --[no-]transitive Show transitive dependencies. -[ERR] (defaults to off in --mode=null-safety). -[ERR] -C, --directory=<dir> Run this in the directory<dir>. -[ERR] -[ERR] Run "pub help" to see global options. -[ERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation. -[Exit code] 64 -
diff --git a/test/outdated/goldens/no_pubspec.txt b/test/outdated/goldens/no_pubspec.txt deleted file mode 100644 index ec3a40a..0000000 --- a/test/outdated/goldens/no_pubspec.txt +++ /dev/null
@@ -1,4 +0,0 @@ -$ pub outdated -[ERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp". -[Exit code] 66 -
diff --git a/test/outdated/outdated_test.dart b/test/outdated/outdated_test.dart index 925e0de..31113c7 100644 --- a/test/outdated/outdated_test.dart +++ b/test/outdated/outdated_test.dart
@@ -2,75 +2,67 @@ // 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. -// @dart=2.10 - -import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../golden_file.dart'; import '../test_pub.dart'; -/// Try running 'pub outdated' with a number of different sets of arguments. -/// -/// Compare the stdout and stderr output to the file in goldens/$[name]. -Future<void> variations(String name, {Map<String, String> environment}) async { - final buffer = StringBuffer(); - for (final args in [ - ['outdated', '--json'], - ['outdated', '--no-color'], - ['outdated', '--no-color', '--no-transitive'], - ['outdated', '--no-color', '--up-to-date'], - ['outdated', '--no-color', '--prereleases'], - ['outdated', '--no-color', '--no-dev-dependencies'], - ['outdated', '--no-color', '--no-dependency-overrides'], - ['outdated', '--no-color', '--mode=null-safety'], - ['outdated', '--no-color', '--mode=null-safety', '--transitive'], - ['outdated', '--no-color', '--mode=null-safety', '--no-prereleases'], - ['outdated', '--json', '--mode=null-safety'], - ['outdated', '--json', '--no-dev-dependencies'], - ]) { - await runPubIntoBuffer(args, buffer, environment: environment); +extension on GoldenTestContext { + /// Try running 'pub outdated' with a number of different sets of arguments. + /// And compare to results from test/testdata/goldens/... + Future<void> runOutdatedTests({ + Map<String, String>? environment, + String? workingDirectory, + }) async { + const commands = [ + ['outdated', '--json'], + ['outdated', '--no-color'], + ['outdated', '--no-color', '--no-transitive'], + ['outdated', '--no-color', '--up-to-date'], + ['outdated', '--no-color', '--prereleases'], + ['outdated', '--no-color', '--no-dev-dependencies'], + ['outdated', '--no-color', '--no-dependency-overrides'], + ['outdated', '--no-color', '--mode=null-safety'], + ['outdated', '--no-color', '--mode=null-safety', '--transitive'], + ['outdated', '--no-color', '--mode=null-safety', '--no-prereleases'], + ['outdated', '--json', '--mode=null-safety'], + ['outdated', '--json', '--no-dev-dependencies'], + ]; + for (final args in commands) { + await run( + args, + environment: environment, + workingDirectory: workingDirectory, + ); + } } - // The easiest way to update the golden files is to delete them and rerun the - // test. - expectMatchesGoldenFile(buffer.toString(), 'test/outdated/goldens/$name.txt'); } Future<void> main() async { - test('help text', () async { - final buffer = StringBuffer(); - await runPubIntoBuffer( - ['outdated', '--help'], - buffer, - ); - expectMatchesGoldenFile( - buffer.toString(), 'test/outdated/goldens/helptext.txt'); - }); - - test('no pubspec', () async { + testWithGolden('no pubspec', (ctx) async { await d.dir(appPath, []).create(); - final buffer = StringBuffer(); - await runPubIntoBuffer(['outdated'], buffer); - expectMatchesGoldenFile( - buffer.toString(), 'test/outdated/goldens/no_pubspec.txt'); + await ctx.run(['outdated']); }); - test('no lockfile', () async { + testWithGolden('no lockfile', (ctx) async { await d.appDir({'foo': '^1.0.0', 'bar': '^1.0.0'}).create(); - await servePackages((builder) => builder + await servePackages() ..serve('foo', '1.2.3') ..serve('bar', '1.2.3') - ..serve('bar', '2.0.0')); - await variations('no_lockfile'); + ..serve('bar', '2.0.0'); + + await ctx.runOutdatedTests(); }); - test('no dependencies', () async { + testWithGolden('no dependencies', (ctx) async { await d.appDir().create(); await pubGet(); - await variations('no_dependencies'); + + await ctx.runOutdatedTests(); }); - test('newer versions available', () async { - await servePackages((builder) => builder + testWithGolden('newer versions available', (ctx) async { + final builder = await servePackages(); + builder ..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'}) ..serve('bar', '1.0.0') ..serve('builder', '1.2.3', deps: { @@ -78,7 +70,7 @@ 'dev_trans': '^1.0.0', }) ..serve('transitive', '1.2.3') - ..serve('dev_trans', '1.0.0')); + ..serve('dev_trans', '1.0.0'); await d.dir('local_package', [ d.libDir('local_package'), @@ -97,7 +89,7 @@ }) ]).create(); await pubGet(); - globalPackageServer.add((builder) => builder + builder ..serve('foo', '1.3.0', deps: {'transitive': '>=1.0.0<3.0.0'}) ..serve('foo', '2.0.0', deps: {'transitive': '>=1.0.0<3.0.0', 'transitive2': '^1.0.0'}) @@ -113,14 +105,13 @@ ..serve('transitive', '2.0.0') ..serve('transitive2', '1.0.0') ..serve('transitive3', '1.0.0') - ..serve('dev_trans', '2.0.0')); - await variations('newer_versions'); + ..serve('dev_trans', '2.0.0'); + await ctx.runOutdatedTests(); }); - test('circular dependency on root', () async { - await servePackages( - (builder) => builder..serve('foo', '1.2.3', deps: {'app': '^1.0.0'}), - ); + testWithGolden('circular dependency on root', (ctx) async { + final server = await servePackages(); + server.serve('foo', '1.2.3', deps: {'app': '^1.0.0'}); await d.dir(appPath, [ d.pubspec({ @@ -134,13 +125,11 @@ await pubGet(); - globalPackageServer.add( - (builder) => builder..serve('foo', '1.3.0', deps: {'app': '^1.0.1'}), - ); - await variations('circular_dependencies'); + server.serve('foo', '1.3.0', deps: {'app': '^1.0.1'}); + await ctx.runOutdatedTests(); }); - test('mutually incompatible newer versions', () async { + testWithGolden('mutually incompatible newer versions', (ctx) async { await d.dir(appPath, [ d.pubspec({ 'name': 'app', @@ -152,17 +141,17 @@ }) ]).create(); - await servePackages((builder) => builder + await servePackages() ..serve('foo', '1.0.0', deps: {'bar': '^1.0.0'}) ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'}) ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) - ..serve('bar', '2.0.0', deps: {'foo': '^1.0.0'})); + ..serve('bar', '2.0.0', deps: {'foo': '^1.0.0'}); await pubGet(); - await variations('mutually_incompatible'); + await ctx.runOutdatedTests(); }); - test('null safety compliance', () async { + testWithGolden('null safety compliance', (ctx) async { await d.dir(appPath, [ d.pubspec({ 'name': 'app', @@ -179,70 +168,69 @@ }), ]).create(); - await servePackages( - (builder) => builder - ..serve('foo', '1.0.0', deps: { - 'bar': '^1.0.0' - }, pubspec: { - 'environment': {'sdk': '>=2.9.0 < 3.0.0'} - }) - ..serve('bar', '1.0.0', pubspec: { - 'environment': {'sdk': '>=2.9.0 < 3.0.0'} - }) - ..serve('foo', '2.0.0-nullsafety.0', deps: { - 'bar': '^2.0.0' - }, pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'} - }) - ..serve('foo', '2.0.0', deps: { - 'bar': '^1.0.0' - }, pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'} - }) - ..serve('bar', '2.0.0', pubspec: { - 'environment': {'sdk': '>=2.13.0 < 3.0.0'} - }) - ..serve('file_opts_out', '1.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }, contents: [ - d.dir('lib', [d.file('main.dart', '// @dart = 2.9\n')]) - ]) - ..serve('file_opts_out', '2.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }) - ..serve('fails_analysis', '1.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }, contents: [ - d.dir('lib', [d.file('main.dart', 'syntax error\n')]) - ]) - ..serve('fails_analysis', '2.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }) - ..serve('file_in_dependency_opts_out', '1.0.0', deps: { - 'file_opts_out': '^1.0.0' - }, pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }) - ..serve('file_in_dependency_opts_out', '2.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }) - ..serve('fails_analysis_in_dependency', '1.0.0', deps: { - 'fails_analysis': '^1.0.0' - }, pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }) - ..serve('fails_analysis_in_dependency', '2.0.0', pubspec: { - 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, - }), - ); + await servePackages() + ..serve('foo', '1.0.0', deps: { + 'bar': '^1.0.0' + }, pubspec: { + 'environment': {'sdk': '>=2.9.0 < 3.0.0'} + }) + ..serve('bar', '1.0.0', pubspec: { + 'environment': {'sdk': '>=2.9.0 < 3.0.0'} + }) + ..serve('foo', '2.0.0-nullsafety.0', deps: { + 'bar': '^2.0.0' + }, pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'} + }) + ..serve('foo', '2.0.0', deps: { + 'bar': '^1.0.0' + }, pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'} + }) + ..serve('bar', '2.0.0', pubspec: { + 'environment': {'sdk': '>=2.13.0 < 3.0.0'} + }) + ..serve('file_opts_out', '1.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }, contents: [ + d.dir('lib', [d.file('main.dart', '// @dart = 2.9\n')]) + ]) + ..serve('file_opts_out', '2.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }) + ..serve('fails_analysis', '1.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }, contents: [ + d.dir('lib', [d.file('main.dart', 'syntax error\n')]) + ]) + ..serve('fails_analysis', '2.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }) + ..serve('file_in_dependency_opts_out', '1.0.0', deps: { + 'file_opts_out': '^1.0.0' + }, pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }) + ..serve('file_in_dependency_opts_out', '2.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }) + ..serve('fails_analysis_in_dependency', '1.0.0', deps: { + 'fails_analysis': '^1.0.0' + }, pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }) + ..serve('fails_analysis_in_dependency', '2.0.0', pubspec: { + 'environment': {'sdk': '>=2.12.0 < 3.0.0'}, + }); await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); - await variations('null_safety', - environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); + await ctx.runOutdatedTests(environment: { + '_PUB_TEST_SDK_VERSION': '2.13.0', + }); }); - test('null-safety no resolution', () async { - await servePackages((builder) => builder + testWithGolden('null-safety no resolution', (ctx) async { + await servePackages() ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0 < 3.0.0'} }) @@ -258,7 +246,7 @@ 'foo': '^1.0.0' }, pubspec: { 'environment': {'sdk': '>=2.12.0 < 3.0.0'} - })); + }); await d.dir(appPath, [ d.pubspec({ @@ -274,12 +262,13 @@ await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); - await variations('null_safety_no_resolution', - environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); + await ctx.runOutdatedTests(environment: { + '_PUB_TEST_SDK_VERSION': '2.13.0', + }); }); - test('null-safety already migrated', () async { - await servePackages((builder) => builder + testWithGolden('null-safety already migrated', (ctx) async { + await servePackages() ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0 < 3.0.0'} }) @@ -296,7 +285,7 @@ }) ..serve('devTransitive', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0 < 3.0.0'} - })); + }); await d.dir(appPath, [ d.pubspec({ @@ -314,21 +303,20 @@ await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); - await variations('null_safety_already_migrated', - environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}); + await ctx.runOutdatedTests(environment: { + '_PUB_TEST_SDK_VERSION': '2.13.0', + }); }); - test('overridden dependencies', () async { + testWithGolden('overridden dependencies', (ctx) async { ensureGit(); - await servePackages( - (builder) => builder - ..serve('foo', '1.0.0') - ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) - ..serve('bar', '1.0.0') - ..serve('bar', '2.0.0') - ..serve('baz', '1.0.0') - ..serve('baz', '2.0.0'), - ); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) + ..serve('bar', '1.0.0') + ..serve('bar', '2.0.0') + ..serve('baz', '1.0.0') + ..serve('baz', '2.0.0'); await d.git('foo.git', [ d.libPubspec('foo', '1.0.1'), @@ -359,18 +347,16 @@ await pubGet(); - await variations('dependency_overrides'); + await ctx.runOutdatedTests(); }); - test('overridden dependencies - no resolution', () async { + testWithGolden('overridden dependencies - no resolution', (ctx) async { ensureGit(); - await servePackages( - (builder) => builder - ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'}) - ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) - ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'}) - ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}), - ); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'}) + ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) + ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'}) + ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}); await d.dir(appPath, [ d.pubspec({ @@ -389,13 +375,13 @@ await pubGet(); - await variations('dependency_overrides_no_solution'); + await ctx.runOutdatedTests(); }); - test( + testWithGolden( 'latest version reported while locked on a prerelease can be a prerelease', - () async { - await servePackages((builder) => builder + (ctx) async { + await servePackages() ..serve('foo', '0.9.0') ..serve('foo', '1.0.0-dev.1') ..serve('foo', '1.0.0-dev.2') @@ -404,7 +390,7 @@ ..serve('bar', '1.0.0-dev.2') ..serve('mop', '0.10.0-dev') ..serve('mop', '0.10.0') - ..serve('mop', '1.0.0-dev')); + ..serve('mop', '1.0.0-dev'); await d.dir(appPath, [ d.pubspec({ 'name': 'app', @@ -419,11 +405,11 @@ await pubGet(); - await variations('prereleases'); + await ctx.runOutdatedTests(); }); - test('Handles SDK dependencies', () async { - await servePackages((builder) => builder + testWithGolden('Handles SDK dependencies', (ctx) async { + await servePackages() ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.10.0 <3.0.0'} }) @@ -432,7 +418,7 @@ }) ..serve('foo', '2.0.0', pubspec: { 'environment': {'sdk': '>=2.12.0 <3.0.0'} - })); + }); await d.dir('flutter-root', [ d.file('version', '1.2.3'), @@ -471,7 +457,7 @@ '_PUB_TEST_SDK_VERSION': '2.13.0' }); - await variations('handles_sdk_dependencies', environment: { + await ctx.runOutdatedTests(environment: { 'FLUTTER_ROOT': d.path('flutter-root'), '_PUB_TEST_SDK_VERSION': '2.13.0', // To test that the reproduction command is reflected correctly. @@ -479,11 +465,8 @@ }); }); - test("doesn't allow arguments. Handles bad flags", () async { - final sb = StringBuffer(); - await runPubIntoBuffer(['outdated', 'random_argument'], sb); - await runPubIntoBuffer(['outdated', '--bad_flag'], sb); - expectMatchesGoldenFile( - sb.toString(), 'test/outdated/goldens/bad_arguments.txt'); + testWithGolden('does not allow arguments - handles bad flags', (ctx) async { + await ctx.run(['outdated', 'random_argument']); + await ctx.run(['outdated', '--bad_flag']); }); }
diff --git a/test/package_config_file_test.dart b/test/package_config_file_test.dart index 8cb03f0..763ce42 100644 --- a/test/package_config_file_test.dart +++ b/test/package_config_file_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -14,13 +12,12 @@ void main() { forBothPubGetAndUpgrade((command) { test('package_config.json file is created', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]); - builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]); - builder.serve('baz', '2.2.2', + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]) + ..serve('bar', '3.2.1', contents: [d.dir('lib', [])]) + ..serve('baz', '2.2.2', deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]); - }); await d.dir(appPath, [ d.appPubspec({'foo': '1.2.3'}), @@ -56,13 +53,12 @@ }); test('package_config.json file is overwritten', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]); - builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]); - builder.serve('baz', '2.2.2', + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]) + ..serve('bar', '3.2.1', contents: [d.dir('lib', [])]) + ..serve('baz', '2.2.2', deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]); - }); await d.dir(appPath, [ d.appPubspec({'foo': '1.2.3'}), @@ -119,6 +115,8 @@ args: ['--offline'], error: equalsIgnoringWhitespace(""" Because myapp depends on foo any which doesn't exist (could not find package foo in cache), version solving failed. + + Try again without --offline! """), exitCode: exit_codes.UNAVAILABLE); await d.dir(appPath, [ @@ -129,11 +127,10 @@ test( '.dart_tool/package_config.json file has relative path to path dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': 'any'}, contents: [d.dir('lib', [])]); - builder.serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]); - }); + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': 'any'}, contents: [d.dir('lib', [])]) + ..serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]); await d.dir('local_baz', [ d.libDir('baz', 'baz 3.2.1'), @@ -180,18 +177,17 @@ }); test('package_config.json has language version', () async { - await servePackages((builder) { - builder.serve( - 'foo', - '1.2.3', - pubspec: { - 'environment': { - 'sdk': '>=0.0.1 <=0.2.2+2', // tests runs with '0.1.2+3' - }, + final server = await servePackages(); + server.serve( + 'foo', + '1.2.3', + pubspec: { + 'environment': { + 'sdk': '>=0.0.1 <=0.2.2+2', // tests runs with '0.1.2+3' }, - contents: [d.dir('lib', [])], - ); - }); + }, + contents: [d.dir('lib', [])], + ); await d.dir(appPath, [ d.pubspec({ @@ -225,18 +221,17 @@ }); test('package_config.json has 2.7 default language version', () async { - await servePackages((builder) { - builder.serve( - 'foo', - '1.2.3', - pubspec: { - 'environment': { - 'sdk': 'any', - }, + final server = await servePackages(); + server.serve( + 'foo', + '1.2.3', + pubspec: { + 'environment': { + 'sdk': 'any', }, - contents: [d.dir('lib', [])], - ); - }); + }, + contents: [d.dir('lib', [])], + ); await d.dir(appPath, [ d.pubspec({
diff --git a/test/package_list_files_test.dart b/test/package_list_files_test.dart index 7891270..091001b 100644 --- a/test/package_list_files_test.dart +++ b/test/package_list_files_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as p; @@ -15,8 +13,8 @@ import 'descriptor.dart' as d; import 'test_pub.dart'; -String root; -Entrypoint entrypoint; +late String root; +Entrypoint? entrypoint; void main() { test('lists files recursively', () async { @@ -35,7 +33,7 @@ createEntrypoint(); expect( - entrypoint.root.listFiles(), + entrypoint!.root.listFiles(), unorderedEquals([ p.join(root, 'pubspec.yaml'), p.join(root, 'file1.txt'), @@ -71,7 +69,7 @@ createEntrypoint(); expect( - () => entrypoint.root.listFiles(), + () => entrypoint!.root.listFiles(), throwsA( isA<DataException>().having( (e) => e.message, @@ -123,7 +121,7 @@ createEntrypoint(); expect( - () => entrypoint.root.listFiles(), + () => entrypoint!.root.listFiles(), throwsA( isA<DataException>().having( (e) => e.message, @@ -151,7 +149,7 @@ createEntrypoint(); expect( - () => entrypoint.root.listFiles(), + () => entrypoint!.root.listFiles(), throwsA( isA<DataException>().having( (e) => e.message, @@ -169,13 +167,13 @@ d.file('.foo', ''), ]).create(); createEntrypoint(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, '.foo'), p.join(root, 'pubspec.yaml'), }); }); group('with git', () { - d.GitRepoDescriptor repo; + late d.GitRepoDescriptor repo; setUp(() async { ensureGit(); repo = d.git(appPath, [d.appPubspec()]); @@ -193,7 +191,7 @@ ]) ]).create(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file1.txt'), p.join(root, 'file2.txt'), @@ -213,7 +211,7 @@ ]) ]).create(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file2.text'), p.join(root, 'subdir', 'subfile2.text') @@ -246,7 +244,7 @@ createEntrypoint(p.join(appPath, 'rep', 'sub')); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'file2.text'), p.join(root, 'file4.gak'), @@ -254,6 +252,23 @@ }); }); + test("Don't ignore packages/ before the package root", () async { + await d.dir(appPath, [ + d.dir('packages', [ + d.dir('app', [ + d.appPubspec(), + d.dir('packages', [d.file('a.txt')]), + ]), + ]), + ]).create(); + + createEntrypoint(p.join(appPath, 'packages', 'app')); + + expect(entrypoint!.root.listFiles(), { + p.join(root, 'pubspec.yaml'), + }); + }); + group('with a submodule', () { setUp(() async { await d.git('submodule', [ @@ -269,7 +284,7 @@ }); test('respects its .gitignore with useGitIgnore', () { - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'submodule', 'file2.text'), }); @@ -282,7 +297,7 @@ d.dir('subdir', [d.file('pubspec.lock')]) ]).create(); - expect(entrypoint.root.listFiles(), {p.join(root, 'pubspec.yaml')}); + expect(entrypoint!.root.listFiles(), {p.join(root, 'pubspec.yaml')}); }); test('ignores packages directories', () async { @@ -293,7 +308,7 @@ ]) ]).create(); - expect(entrypoint.root.listFiles(), {p.join(root, 'pubspec.yaml')}); + expect(entrypoint!.root.listFiles(), {p.join(root, 'pubspec.yaml')}); }); test('allows pubspec.lock directories', () async { @@ -303,7 +318,7 @@ ]) ]).create(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'pubspec.lock', 'file.txt') }); @@ -324,7 +339,7 @@ ]) ]).create(); - expect(entrypoint.root.listFiles(beneath: 'subdir'), { + expect(entrypoint!.root.listFiles(beneath: 'subdir'), { p.join(root, 'subdir', 'subfile1.txt'), p.join(root, 'subdir', 'subfile2.txt'), p.join(root, 'subdir', 'subsubdir', 'subsubfile1.txt'), @@ -343,7 +358,7 @@ d.dir('lib', [d.file('not_ignored.dart', 'content')]), ]).create(); createEntrypoint(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'LICENSE'), p.join(root, 'CHANGELOG.md'), p.join(root, 'README.md'), @@ -395,7 +410,7 @@ ]).create(); createEntrypoint(); - expect(entrypoint.root.listFiles(), { + expect(entrypoint!.root.listFiles(), { p.join(root, 'pubspec.yaml'), p.join(root, 'not_ignored_by_gitignore.txt'), p.join(root, 'ignored_by_gitignore.txt'), @@ -410,7 +425,7 @@ }); } -void createEntrypoint([String path]) { +void createEntrypoint([String? path]) { path ??= appPath; root = p.join(d.sandbox, path); entrypoint = Entrypoint(root, SystemCache(rootDir: root));
diff --git a/test/package_server.dart b/test/package_server.dart index ec960ca..952c189 100644 --- a/test/package_server.dart +++ b/test/package_server.dart
@@ -2,162 +2,158 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:path/path.dart' as p; +import 'package:pub/src/third_party/tar/tar.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:shelf/shelf.dart' as shelf; +import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:test/test.dart'; import 'package:test/test.dart' as test show expect; import 'descriptor.dart' as d; import 'test_pub.dart'; -/// The current global [PackageServer]. -PackageServer get globalPackageServer => _globalPackageServer; -PackageServer _globalPackageServer; - -/// Creates an HTTP server that replicates the structure of pub.dartlang.org and -/// makes it the current [globalServer]. -/// -/// Calls [callback] with a [PackageServerBuilder] that's used to specify -/// which packages to serve. -Future servePackages([void Function(PackageServerBuilder) callback]) async { - _globalPackageServer = await PackageServer.start(callback ?? (_) {}); - globalServer = _globalPackageServer._inner; - - addTearDown(() { - _globalPackageServer = null; - }); -} - -/// Like [servePackages], but instead creates an empty server with no packages -/// registered. -/// -/// This will always replace a previous server. -Future serveNoPackages() => servePackages((_) {}); - -/// Sets up the global package server to report an error on any request. -/// -/// If no server has been set up, an empty server will be started. -Future serveErrors() async { - if (globalPackageServer == null) { - await serveNoPackages(); - } - globalPackageServer.serveErrors(); -} - class PackageServer { /// The inner [DescriptorServer] that this uses to serve its descriptors. - final DescriptorServer _inner; + final shelf.Server _inner; - /// The [d.DirectoryDescriptor] describing the server layout of - /// `/api/packages` on the test server. - /// - /// This contains metadata for packages that are being served via - /// [servePackages]. - final _servedApiPackageDir = d.dir('packages', []); + /// Handlers of requests. Last matching handler will be used. + final List<_PatternAndHandler> _handlers = []; - /// The [d.DirectoryDescriptor] describing the server layout of `/packages` on - /// the test server. - /// - /// This contains the tarballs for packages that are being served via - /// [servePackages]. - final _servedPackageDir = d.dir('packages', []); + // A list of all the requests recieved up till now. + final List<String> requestedPaths = <String>[]; - /// The current [PackageServerBuilder] that a user uses to specify which - /// package to serve. - /// - /// This is preserved so that additional packages can be added. - PackageServerBuilder _builder; + PackageServer._(this._inner) { + _inner.mount((request) { + final path = request.url.path; + requestedPaths.add(path); - /// The port used for the server. - int get port => _inner.port; + final pathWithInitialSlash = '/$path'; + for (final entry in _handlers.reversed) { + final match = entry.pattern.matchAsPrefix(pathWithInitialSlash); + if (match != null && match.end == pathWithInitialSlash.length) { + final a = entry.handler(request); + return a; + } + } + return shelf.Response.notFound('Could not find ${request.url}'); + }); + } - /// The URL for the server. - String get url => 'http://localhost:$port'; + static final _versionInfoPattern = RegExp(r'/api/packages/([a-zA-Z_0-9]*)'); + static final _downloadPattern = + RegExp(r'/packages/([^/]*)/versions/([^/]*).tar.gz'); - /// Handlers for requests not easily described as packages. - Map<Pattern, shelf.Handler> get extraHandlers => _inner.extraHandlers; + static Future<PackageServer> start() async { + final server = + PackageServer._(await shelf_io.IOServer.bind('localhost', 0)); + server.handle( + _versionInfoPattern, + (shelf.Request request) { + final parts = request.url.pathSegments; + assert(parts[0] == 'api'); + assert(parts[1] == 'packages'); + final name = parts[2]; - /// From now on report errors on any request. - void serveErrors() => extraHandlers - ..clear() - ..[RegExp('.*')] = (request) { - fail('The HTTP server received an unexpected request:\n' - '${request.method} ${request.requestedUri}'); - }; + final package = server._packages[name]; + if (package == null) { + return shelf.Response.notFound('No package named $name'); + } + return shelf.Response.ok(jsonEncode({ + 'name': name, + 'uploaders': ['nweiz@google.com'], + 'versions': package.versions.values + .map((version) => packageVersionApiMap( + server._inner.url.toString(), + version.pubspec, + retracted: version.isRetracted, + )) + .toList(), + if (package.isDiscontinued) 'isDiscontinued': true, + if (package.discontinuedReplacementText != null) + 'replacedBy': package.discontinuedReplacementText, + })); + }, + ); - /// Creates an HTTP server that replicates the structure of pub.dartlang.org. - /// - /// Calls [callback] with a [PackageServerBuilder] that's used to specify - /// which packages to serve. - static Future<PackageServer> start( - void Function(PackageServerBuilder) callback) async { - var descriptorServer = await DescriptorServer.start(); - var server = PackageServer._(descriptorServer); - descriptorServer.contents - ..add(d.dir('api', [server._servedApiPackageDir])) - ..add(server._servedPackageDir); - server.add(callback); + server.handle( + _downloadPattern, + (shelf.Request request) { + final parts = request.url.pathSegments; + assert(parts[0] == 'packages'); + final name = parts[1]; + assert(parts[2] == 'versions'); + final package = server._packages[name]; + if (package == null) { + return shelf.Response.notFound('No package $name'); + } + + final version = Version.parse( + parts[3].substring(0, parts[3].length - '.tar.gz'.length)); + assert(parts[3].endsWith('.tar.gz')); + + for (final packageVersion in package.versions.values) { + if (packageVersion.version == version) { + return shelf.Response.ok(packageVersion.contents()); + } + } + return shelf.Response.notFound('No version $version of $name'); + }, + ); return server; } - PackageServer._(this._inner) { - _builder = PackageServerBuilder._(this); + Future<void> close() async { + await _inner.close(); } - /// Add to the current set of packages that are being served. - void add(void Function(PackageServerBuilder) callback) { - callback(_builder); + /// The port used for the server. + int get port => _inner.url.port; - _servedApiPackageDir.contents.clear(); - _servedPackageDir.contents.clear(); + /// The URL for the server. + String get url => _inner.url.toString(); - _builder._packages.forEach((name, package) { - _servedApiPackageDir.contents.addAll([ - d.file( - name, - jsonEncode({ - 'name': name, - 'uploaders': ['nweiz@google.com'], - 'versions': package.versions.values - .map((version) => packageVersionApiMap(url, version.pubspec, - retracted: version.isRetracted)) - .toList(), - if (package.isDiscontinued) 'isDiscontinued': true, - if (package.discontinuedReplacementText != null) - 'replacedBy': package.discontinuedReplacementText, - })), - d.dir(name, [ - d.dir('versions', package.versions.values.map((version) { - return d.file( - version.version.toString(), - jsonEncode(packageVersionApiMap(url, version.pubspec, - retracted: version.isRetracted, full: true))); - })) - ]) - ]); + /// From now on report errors on any request. + void serveErrors() => _handlers + ..clear() + ..add( + _PatternAndHandler( + RegExp('.*'), + (request) { + fail('The HTTP server received an unexpected request:\n' + '${request.method} ${request.requestedUri}'); + }, + ), + ); - _servedPackageDir.contents.add(d.dir(name, [ - d.dir( - 'versions', - package.versions.values.map((version) => - d.tar('${version.version}.tar.gz', version.contents))) - ])); - }); + void handle(Pattern pattern, shelf.Handler handler) { + _handlers.add( + _PatternAndHandler( + pattern, + handler, + ), + ); } // Installs a handler at [pattern] that expects to be called exactly once with // the given [method]. + // + // The handler is installed as the start to give it priority over more general + // handlers. void expect(String method, Pattern pattern, shelf.Handler handler) { - extraHandlers[pattern] = expectAsync1((request) { - test.expect(request.method, method); - return handler(request); - }); + handle( + pattern, + expectAsync1( + (request) { + test.expect(request.method, method); + return handler(request); + }, + ), + ); } /// Returns the path of [package] at [version], installed from this server, in @@ -169,26 +165,9 @@ String get cachingPath => p.join(d.sandbox, cachePath, 'hosted', 'localhost%58$port'); - /// Replace the current set of packages that are being served. - void replace(void Function(PackageServerBuilder) callback) { - _builder._clear(); - add(callback); - } -} - -/// A builder for specifying which packages should be served by [servePackages]. -class PackageServerBuilder { /// A map from package names to the concrete packages to serve. final _packages = <String, _ServedPackage>{}; - /// The package server that this builder is associated with. - final PackageServer _server; - - /// The URL for the server that this builder is associated with. - String get serverUrl => _server.url; - - PackageServerBuilder._(this._server); - /// Specifies that a package named [name] with [version] should be served. /// /// If [deps] is passed, it's used as the "dependencies" field of the pubspec. @@ -197,9 +176,9 @@ /// If [contents] is passed, it's used as the contents of the package. By /// default, a package just contains a dummy lib directory. void serve(String name, String version, - {Map<String, dynamic> deps, - Map<String, dynamic> pubspec, - Iterable<d.Descriptor> contents}) { + {Map<String, dynamic>? deps, + Map<String, dynamic>? pubspec, + List<d.Descriptor>? contents}) { var pubspecFields = <String, dynamic>{'name': name, 'version': version}; if (pubspec != null) pubspecFields.addAll(pubspec); if (deps != null) pubspecFields['dependencies'] = deps; @@ -208,40 +187,84 @@ contents = [d.file('pubspec.yaml', yaml(pubspecFields)), ...contents]; var package = _packages.putIfAbsent(name, () => _ServedPackage()); - package.versions[version] = _ServedPackageVersion(pubspecFields, contents); + package.versions[version] = _ServedPackageVersion( + pubspecFields, + contents: () { + final entries = <TarEntry>[]; + + void addDescriptor(d.Descriptor descriptor, String path) { + if (descriptor is d.DirectoryDescriptor) { + for (final e in descriptor.contents) { + addDescriptor(e, p.posix.join(path, descriptor.name)); + } + } else { + entries.add( + TarEntry( + TarHeader( + // Ensure paths in tar files use forward slashes + name: p.posix.join(path, descriptor.name), + // We want to keep executable bits, but otherwise use the default + // file mode + mode: 420, + // size: 100, + modified: DateTime.now(), + userName: 'pub', + groupName: 'pub', + ), + (descriptor as d.FileDescriptor).readAsBytes(), + ), + ); + } + } + + for (final e in contents ?? <d.Descriptor>[]) { + addDescriptor(e, ''); + } + return Stream.fromIterable(entries) + .transform(tarWriterWith(format: OutputFormat.gnuLongName)) + .transform(gzip.encoder); + }, + ); } // Mark a package discontinued. void discontinue(String name, - {bool isDiscontinued = true, String replacementText}) { - _packages[name] + {bool isDiscontinued = true, String? replacementText}) { + _packages[name]! ..isDiscontinued = isDiscontinued ..discontinuedReplacementText = replacementText; } /// Clears all existing packages from this builder. - void _clear() { + void clearPackages() { _packages.clear(); } void retractPackageVersion(String name, String version) { - _packages[name].versions[version].isRetracted = true; + _packages[name]!.versions[version]!.isRetracted = true; } } class _ServedPackage { final versions = <String, _ServedPackageVersion>{}; bool isDiscontinued = false; - String discontinuedReplacementText; + String? discontinuedReplacementText; } /// A package that's intended to be served. class _ServedPackageVersion { final Map pubspec; - final List<d.Descriptor> contents; + final Stream<List<int>> Function() contents; bool isRetracted = false; Version get version => Version.parse(pubspec['version']); - _ServedPackageVersion(this.pubspec, this.contents); + _ServedPackageVersion(this.pubspec, {required this.contents}); +} + +class _PatternAndHandler { + Pattern pattern; + shelf.Handler handler; + + _PatternAndHandler(this.pattern, this.handler); }
diff --git a/test/packages_file_test.dart b/test/packages_file_test.dart index ce87d7c..c245a9a 100644 --- a/test/packages_file_test.dart +++ b/test/packages_file_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -13,21 +11,20 @@ void main() { forBothPubGetAndUpgrade((command) { - test('.packages file is created', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]); - builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]); - builder.serve('baz', '2.2.2', + test('.packages file is created with flag', () async { + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]) + ..serve('bar', '3.2.1', contents: [d.dir('lib', [])]) + ..serve('baz', '2.2.2', deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]); - }); await d.dir(appPath, [ d.appPubspec({'foo': '1.2.3'}), d.dir('lib') ]).create(); - await pubCommand(command); + await pubCommand(command, args: ['--legacy-packages-file']); await d.dir(appPath, [ d.packagesFile( @@ -35,14 +32,13 @@ ]).validate(); }); - test('.packages file is overwritten', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]); - builder.serve('bar', '3.2.1', contents: [d.dir('lib', [])]); - builder.serve('baz', '2.2.2', + test('.packages file is overwritten with flag', () async { + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': '2.2.2'}, contents: [d.dir('lib', [])]) + ..serve('bar', '3.2.1', contents: [d.dir('lib', [])]) + ..serve('baz', '2.2.2', deps: {'bar': '3.2.1'}, contents: [d.dir('lib', [])]); - }); await d.dir(appPath, [ d.appPubspec({'foo': '1.2.3'}), @@ -55,7 +51,7 @@ await oldFile.create(); await oldFile.validate(); // Sanity-check that file was created correctly. - await pubCommand(command); + await pubCommand(command, args: ['--legacy-packages-file']); await d.dir(appPath, [ d.packagesFile( @@ -63,27 +59,32 @@ ]).validate(); }); - test('.packages file is not created if pub command fails', () async { + test('.packages file is not created if pub command fails with flag', + () async { await d.dir(appPath, [ d.appPubspec({'foo': '1.2.3'}), d.dir('lib') ]).create(); await pubCommand(command, - args: ['--offline'], error: equalsIgnoringWhitespace(""" + args: ['--offline', '--legacy-packages-file'], + error: equalsIgnoringWhitespace(""" Because myapp depends on foo any which doesn't exist (could not find package foo in cache), version solving failed. - """), exitCode: exit_codes.UNAVAILABLE); + + Try again without --offline! + """), + exitCode: exit_codes.UNAVAILABLE); await d.dir(appPath, [d.nothing('.packages')]).validate(); }); - test('.packages file has relative path to path dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', - deps: {'baz': 'any'}, contents: [d.dir('lib', [])]); - builder.serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]); - }); + test('.packages file has relative path to path dependency with flag', + () async { + await servePackages() + ..serve('foo', '1.2.3', + deps: {'baz': 'any'}, contents: [d.dir('lib', [])]) + ..serve('baz', '9.9.9', deps: {}, contents: [d.dir('lib', [])]); await d.dir('local_baz', [ d.libDir('baz', 'baz 3.2.1'), @@ -103,7 +104,7 @@ d.dir('lib') ]).create(); - await pubCommand(command); + await pubCommand(command, args: ['--legacy-packages-file']); await d.dir(appPath, [ d.packagesFile({'myapp': '.', 'baz': '../local_baz', 'foo': '1.2.3'}),
diff --git a/test/pub_get_and_upgrade_test.dart b/test/pub_get_and_upgrade_test.dart index b93d10f..f64f93b 100644 --- a/test/pub_get_and_upgrade_test.dart +++ b/test/pub_get_and_upgrade_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -47,7 +45,8 @@ await pubCommand(command); await d.dir('myapp', [ - d.packagesFile({'myapp_name': '.'}) + d.packageConfigFile( + [d.packageConfigEntry(name: 'myapp_name', path: '.')]), ]).validate(); });
diff --git a/test/pub_uploader_test.dart b/test/pub_uploader_test.dart index 98bd2fe..47d50d3 100644 --- a/test/pub_uploader_test.dart +++ b/test/pub_uploader_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -15,19 +13,6 @@ import 'descriptor.dart' as d; import 'test_pub.dart'; -const _usageString = ''' -Manage uploaders for a package on pub.dartlang.org. - -Usage: pub uploader [options] {add/remove} <email> --h, --help Print this usage information. - --package The package whose uploaders will be modified. - (defaults to the current package) --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation. -'''; - Future<TestProcess> startPubUploader(PackageServer server, List<String> args) { var tokenEndpoint = Uri.parse(server.url).resolve('/token').toString(); var allArgs = ['uploader', ...args]; @@ -40,33 +25,26 @@ void main() { group('displays usage', () { test('when run with no arguments', () { - return runPub( - args: ['uploader'], output: _usageString, exitCode: exit_codes.USAGE); + return runPub(args: ['uploader'], exitCode: exit_codes.USAGE); }); test('when run with only a command', () { - return runPub( - args: ['uploader', 'add'], - output: _usageString, - exitCode: exit_codes.USAGE); + return runPub(args: ['uploader', 'add'], exitCode: exit_codes.USAGE); }); test('when run with an invalid command', () { return runPub( - args: ['uploader', 'foo', 'email'], - output: _usageString, - exitCode: exit_codes.USAGE); + args: ['uploader', 'foo', 'email'], exitCode: exit_codes.USAGE); }); }); test('adds an uploader', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'add', 'email']); + globalServer, ['--package', 'pkg', 'add', 'email']); - globalPackageServer.expect('POST', '/api/packages/pkg/uploaders', - (request) { + globalServer.expect('POST', '/api/packages/pkg/uploaders', (request) { return request.readAsString().then((body) { expect(body, equals('email=email')); @@ -84,11 +62,11 @@ test('removes an uploader', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'remove', 'email']); + globalServer, ['--package', 'pkg', 'remove', 'email']); - globalPackageServer.expect('DELETE', '/api/packages/pkg/uploaders/email', + globalServer.expect('DELETE', '/api/packages/pkg/uploaders/email', (request) { return shelf.Response.ok( jsonEncode({ @@ -105,11 +83,10 @@ await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); - var pub = await startPubUploader(globalPackageServer, ['add', 'email']); + await d.credentialsFile(globalServer, 'access token').create(); + var pub = await startPubUploader(globalServer, ['add', 'email']); - globalPackageServer.expect('POST', '/api/packages/test_pkg/uploaders', - (request) { + globalServer.expect('POST', '/api/packages/test_pkg/uploaders', (request) { return shelf.Response.ok( jsonEncode({ 'success': {'message': 'Good job!'} @@ -123,12 +100,11 @@ test('add provides an error', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'add', 'email']); + globalServer, ['--package', 'pkg', 'add', 'email']); - globalPackageServer.expect('POST', '/api/packages/pkg/uploaders', - (request) { + globalServer.expect('POST', '/api/packages/pkg/uploaders', (request) { return shelf.Response(400, body: jsonEncode({ 'error': {'message': 'Bad job!'} @@ -142,11 +118,11 @@ test('remove provides an error', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'remove', 'e/mail']); + globalServer, ['--package', 'pkg', 'remove', 'e/mail']); - globalPackageServer.expect('DELETE', '/api/packages/pkg/uploaders/e%2Fmail', + globalServer.expect('DELETE', '/api/packages/pkg/uploaders/e%2Fmail', (request) { return shelf.Response(400, body: jsonEncode({ @@ -161,11 +137,11 @@ test('add provides invalid JSON', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'add', 'email']); + globalServer, ['--package', 'pkg', 'add', 'email']); - globalPackageServer.expect('POST', '/api/packages/pkg/uploaders', + globalServer.expect('POST', '/api/packages/pkg/uploaders', (request) => shelf.Response.ok('{not json')); expect( @@ -177,11 +153,11 @@ test('remove provides invalid JSON', () async { await servePackages(); - await d.credentialsFile(globalPackageServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access token').create(); var pub = await startPubUploader( - globalPackageServer, ['--package', 'pkg', 'remove', 'email']); + globalServer, ['--package', 'pkg', 'remove', 'email']); - globalPackageServer.expect('DELETE', '/api/packages/pkg/uploaders/email', + globalServer.expect('DELETE', '/api/packages/pkg/uploaders/email', (request) => shelf.Response.ok('{not json')); expect(
diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart index 5785b16..62f77c4 100644 --- a/test/pubspec_test.dart +++ b/test/pubspec_test.dart
@@ -2,8 +2,7 @@ // 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. -// @dart=2.10 - +import 'package:pub/src/language_version.dart'; import 'package:pub/src/package_name.dart'; import 'package:pub/src/pubspec.dart'; import 'package:pub/src/sdk.dart'; @@ -22,14 +21,15 @@ throw UnsupportedError('Cannot download fake packages.'); @override - PackageRef parseRef(String name, description, {String containingPath}) { + PackageRef parseRef(String name, description, + {String? containingPath, LanguageVersion? languageVersion}) { if (description != 'ok') throw FormatException('Bad'); return PackageRef(name, this, description); } @override PackageId parseId(String name, Version version, description, - {String containingPath}) => + {String? containingPath}) => PackageId(name, this, version, description); @override @@ -50,7 +50,7 @@ var throwsPubspecException = throwsA(const TypeMatcher<PubspecException>()); void expectPubspecException(String contents, void Function(Pubspec) fn, - [String expectedContains]) { + [String? expectedContains]) { var expectation = const TypeMatcher<PubspecException>(); if (expectedContains != null) { expectation = expectation.having( @@ -88,7 +88,7 @@ version: ">=1.2.3 <3.4.5" ''', sources); - var foo = pubspec.dependencies['foo']; + var foo = pubspec.dependencies['foo']!; expect(foo.name, equals('foo')); expect(foo.constraint.allows(Version(1, 2, 3)), isTrue); expect(foo.constraint.allows(Version(1, 2, 5)), isTrue); @@ -103,7 +103,7 @@ version: ">=1.2.3 <0.0.0" ''', sources); - var foo = pubspec.dependencies['foo']; + var foo = pubspec.dependencies['foo']!; expect(foo.name, equals('foo')); expect(foo.constraint.isEmpty, isTrue); }); @@ -124,7 +124,7 @@ version: ">=1.2.3 <3.4.5" ''', sources); - var foo = pubspec.devDependencies['foo']; + var foo = pubspec.devDependencies['foo']!; expect(foo.name, equals('foo')); expect(foo.constraint.allows(Version(1, 2, 3)), isTrue); expect(foo.constraint.allows(Version(1, 2, 5)), isTrue); @@ -147,7 +147,7 @@ version: ">=1.2.3 <3.4.5" ''', sources); - var foo = pubspec.dependencyOverrides['foo']; + var foo = pubspec.dependencyOverrides['foo']!; expect(foo.name, equals('foo')); expect(foo.constraint.allows(Version(1, 2, 3)), isTrue); expect(foo.constraint.allows(Version(1, 2, 5)), isTrue); @@ -169,7 +169,7 @@ unknown: blah ''', sources); - var foo = pubspec.dependencies['foo']; + var foo = pubspec.dependencies['foo']!; expect(foo.name, equals('foo')); expect(foo.source, equals(sources['unknown'])); }); @@ -181,7 +181,7 @@ version: 1.2.3 ''', sources); - var foo = pubspec.dependencies['foo']; + var foo = pubspec.dependencies['foo']!; expect(foo.name, equals('foo')); expect(foo.source, equals(sources['hosted'])); }); @@ -294,6 +294,170 @@ 'local pubspec.'); }); + group('source dependencies', () { + test('with url and name', () { + var pubspec = Pubspec.parse( + ''' +name: pkg +dependencies: + foo: + hosted: + url: https://example.org/pub/ + name: bar +''', + sources, + ); + + var foo = pubspec.dependencies['foo']!; + expect(foo.name, equals('foo')); + expect(foo.source!.name, 'hosted'); + expect(foo.source!.serializeDescription('', foo.description), { + 'url': 'https://example.org/pub/', + 'name': 'bar', + }); + }); + + test('with url only', () { + var pubspec = Pubspec.parse( + ''' +name: pkg +environment: + sdk: ^2.15.0 +dependencies: + foo: + hosted: + url: https://example.org/pub/ +''', + sources, + ); + + var foo = pubspec.dependencies['foo']!; + expect(foo.name, equals('foo')); + expect(foo.source!.name, 'hosted'); + expect(foo.source!.serializeDescription('', foo.description), { + 'url': 'https://example.org/pub/', + 'name': 'foo', + }); + }); + + test('with url as string', () { + var pubspec = Pubspec.parse( + ''' +name: pkg +environment: + sdk: ^2.15.0 +dependencies: + foo: + hosted: https://example.org/pub/ +''', + sources, + ); + + var foo = pubspec.dependencies['foo']!; + expect(foo.name, equals('foo')); + expect(foo.source!.name, 'hosted'); + expect(foo.source!.serializeDescription('', foo.description), { + 'url': 'https://example.org/pub/', + 'name': 'foo', + }); + }); + + test('interprets string description as name for older versions', () { + var pubspec = Pubspec.parse( + ''' +name: pkg +environment: + sdk: ^2.14.0 +dependencies: + foo: + hosted: bar +''', + sources, + ); + + var foo = pubspec.dependencies['foo']!; + expect(foo.name, equals('foo')); + expect(foo.source!.name, 'hosted'); + expect(foo.source!.serializeDescription('', foo.description), { + 'url': 'https://pub.dartlang.org', + 'name': 'bar', + }); + }); + + test( + 'reports helpful span when using new syntax with invalid environment', + () { + var pubspec = Pubspec.parse(''' +name: pkg +environment: + sdk: invalid value +dependencies: + foo: + hosted: https://example.org/pub/ +''', sources); + + expect( + () => pubspec.dependencies, + throwsA( + isA<PubspecException>() + .having((e) => e.span!.text, 'span.text', 'invalid value'), + ), + ); + }, + ); + + test('without a description', () { + var pubspec = Pubspec.parse( + ''' +name: pkg +dependencies: + foo: +''', + sources, + ); + + var foo = pubspec.dependencies['foo']!; + expect(foo.name, equals('foo')); + expect(foo.source!.name, 'hosted'); + expect(foo.source!.serializeDescription('', foo.description), { + 'url': 'https://pub.dartlang.org', + 'name': 'foo', + }); + }); + + group('throws without a min SDK constraint', () { + test('and without a name', () { + expectPubspecException( + ''' +name: pkg +dependencies: + foo: + hosted: + url: https://example.org/pub/ +''', + (pubspec) => pubspec.dependencies, + "The 'name' key must have a string value without a minimum Dart " + 'SDK constraint of 2.15.'); + }); + + test( + 'and a hosted: <value> syntax that looks like an URI was meant', + () { + expectPubspecException( + ''' +name: pkg +dependencies: + foo: + hosted: http://pub.example.org +''', + (pubspec) => pubspec.dependencies, + 'Using `hosted: <url>` is only supported with a minimum SDK constraint of 2.15.', + ); + }, + ); + }); + }); + group('git dependencies', () { test('path must be a string', () { expectPubspecException(''' @@ -548,7 +712,7 @@ ''', sources); expect(pubspec.features, contains('foobar')); - var feature = pubspec.features['foobar']; + var feature = pubspec.features['foobar']!; expect(feature.name, equals('foobar')); expect(feature.onByDefault, isTrue); expect(feature.dependencies, isEmpty); @@ -585,7 +749,7 @@ expect(pubspec.features, contains('foobar')); - var feature = pubspec.features['foobar']; + var feature = pubspec.features['foobar']!; expect(feature.sdkConstraints, containsPair('dart', VersionConstraint.parse('^1.0.0'))); expect(feature.sdkConstraints, @@ -604,7 +768,7 @@ Pubspec.parse('features: {foobar: {default: false}}', sources); expect(pubspec.features, contains('foobar')); - expect(pubspec.features['foobar'].onByDefault, isFalse); + expect(pubspec.features['foobar']!.onByDefault, isFalse); }); test('parses valid dependency specifications', () { @@ -618,7 +782,7 @@ expect(pubspec.features, contains('foobar')); - var feature = pubspec.features['foobar']; + var feature = pubspec.features['foobar']!; expect(feature.name, equals('foobar')); expect(feature.onByDefault, isTrue); expect(feature.dependencies, hasLength(2)); @@ -634,7 +798,7 @@ test('can be null', () { var pubspec = Pubspec.parse('features: {foobar: {requires: null}}', sources); - expect(pubspec.features['foobar'].requires, isEmpty); + expect(pubspec.features['foobar']!.requires, isEmpty); }); test('must be a list', () {
diff --git a/test/pubspec_utils_test.dart b/test/pubspec_utils_test.dart index 60863f4..6622c1c 100644 --- a/test/pubspec_utils_test.dart +++ b/test/pubspec_utils_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/pubspec_utils.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -47,8 +45,10 @@ }); test('works on compatible version union', () { - final constraint1 = VersionConstraint.parse('>=1.2.3 <2.0.0'); - final constraint2 = VersionConstraint.parse('>2.2.3 <=4.0.0'); + final constraint1 = + VersionConstraint.parse('>=1.2.3 <2.0.0') as VersionRange; + final constraint2 = + VersionConstraint.parse('>2.2.3 <=4.0.0') as VersionRange; final constraint = VersionUnion.fromRanges([constraint1, constraint2]); final removedUpperBound = stripUpperBound(constraint) as VersionRange;
diff --git a/test/rate_limited_scheduler_test.dart b/test/rate_limited_scheduler_test.dart index 632efbf..8562b07 100644 --- a/test/rate_limited_scheduler_test.dart +++ b/test/rate_limited_scheduler_test.dart
@@ -2,11 +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. -// @dart=2.10 - import 'dart:async'; -import 'package:pedantic/pedantic.dart'; import 'package:pub/src/rate_limited_scheduler.dart'; import 'package:test/test.dart'; @@ -19,8 +16,8 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } @@ -30,11 +27,11 @@ preschedule('b'); preschedule('c'); await Future.wait( - [isBeingProcessed['a'].future, isBeingProcessed['b'].future]); - expect(isBeingProcessed['c'].isCompleted, isFalse); - completers['a'].complete(); - await isBeingProcessed['c'].future; - completers['c'].complete(); + [isBeingProcessed['a']!.future, isBeingProcessed['b']!.future]); + expect(isBeingProcessed['c']!.isCompleted, isFalse); + completers['a']!.complete(); + await isBeingProcessed['c']!.future; + completers['c']!.complete(); expect(await scheduler.schedule('c'), 'C'); }); }); @@ -45,8 +42,8 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } @@ -57,18 +54,18 @@ preschedule1('a'); preschedule2('b'); preschedule1('c'); - await isBeingProcessed['a'].future; + await isBeingProcessed['a']!.future; // b, c should not start processing due to rate-limiting. - expect(isBeingProcessed['b'].isCompleted, isFalse); - expect(isBeingProcessed['c'].isCompleted, isFalse); + expect(isBeingProcessed['b']!.isCompleted, isFalse); + expect(isBeingProcessed['c']!.isCompleted, isFalse); }); - completers['a'].complete(); + completers['a']!.complete(); // b is removed from the queue, now c should start processing. - await isBeingProcessed['c'].future; - completers['c'].complete(); + await isBeingProcessed['c']!.future; + completers['c']!.complete(); expect(await scheduler.schedule('c'), 'C'); // b is not on the queue anymore. - expect(isBeingProcessed['b'].isCompleted, isFalse); + expect(isBeingProcessed['b']!.isCompleted, isFalse); }); }); @@ -78,27 +75,27 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } final scheduler = RateLimitedScheduler(f, maxConcurrentOperations: 1); - Future b; + Future? b; await scheduler.withPrescheduling((preschedule) async { preschedule('a'); preschedule('b'); - await isBeingProcessed['a'].future; + await isBeingProcessed['a']!.future; // b should not start processing due to rate-limiting. - expect(isBeingProcessed['b'].isCompleted, isFalse); + expect(isBeingProcessed['b']!.isCompleted, isFalse); b = scheduler.schedule('b'); }); - completers['a'].complete(); + completers['a']!.complete(); expect(await scheduler.schedule('a'), 'A'); // b was scheduled, so it should get processed now - await isBeingProcessed['b'].future; - completers['b'].complete(); + await isBeingProcessed['b']!.future; + completers['b']!.complete(); expect(await b, 'B'); }); @@ -107,14 +104,14 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } final scheduler = RateLimitedScheduler(f, maxConcurrentOperations: 2); - completers['a'].complete(); + completers['a']!.complete(); expect(await scheduler.schedule('a'), 'A'); // Would fail if isBeingProcessed['a'] was completed twice expect(await scheduler.schedule('a'), 'A'); @@ -125,8 +122,8 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } @@ -134,12 +131,12 @@ await scheduler.withPrescheduling((preschedule) async { preschedule('a'); preschedule('b'); - await isBeingProcessed['a'].future; + await isBeingProcessed['a']!.future; final cResult = scheduler.schedule('c'); - expect(isBeingProcessed['b'].isCompleted, isFalse); - completers['a'].complete(); - completers['c'].complete(); - await isBeingProcessed['c'].future; + expect(isBeingProcessed['b']!.isCompleted, isFalse); + completers['a']!.complete(); + completers['c']!.complete(); + await isBeingProcessed['c']!.future; // 'c' is done before we allow 'b' to finish processing expect(await cResult, 'C'); }); @@ -150,8 +147,8 @@ final isBeingProcessed = threeCompleters(); Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return i.toUpperCase(); } @@ -161,14 +158,15 @@ preschedule('a'); preschedule('b'); preschedule('c'); - await isBeingProcessed['a'].future; - await isBeingProcessed['b'].future; - expect(isBeingProcessed['c'].isCompleted, isFalse); - unawaited(completers['c'].future.catchError((_) {})); - completers['c'].completeError('errorC'); - completers['a'].completeError('errorA'); - await isBeingProcessed['c'].future; - completers['b'].completeError('errorB'); + + await isBeingProcessed['a']!.future; + await isBeingProcessed['b']!.future; + expect(isBeingProcessed['c']!.isCompleted, isFalse); + unawaited(completers['c']!.future.catchError((_) {})); + completers['c']!.completeError('errorC'); + completers['a']!.completeError('errorA'); + await isBeingProcessed['c']!.future; + completers['b']!.completeError('errorB'); expect(() async => await scheduler.schedule('a'), throwsA('errorA')); expect(() async => await scheduler.schedule('b'), throwsA('errorB')); expect(() async => await scheduler.schedule('c'), throwsA('errorC')); @@ -179,9 +177,9 @@ final completers = threeCompleters(); final isBeingProcessed = threeCompleters(); - Future<String> f(String i) async { - isBeingProcessed[i].complete(); - await completers[i].future; + Future<String?> f(String i) async { + isBeingProcessed[i]!.complete(); + await completers[i]!.future; return Zone.current['zoneValue']; } @@ -198,16 +196,16 @@ }, zoneValues: {'zoneValue': 'C'}); await runZoned(() async { - await isBeingProcessed['a'].future; - await isBeingProcessed['b'].future; + await isBeingProcessed['a']!.future; + await isBeingProcessed['b']!.future; // This will put 'c' in front of the queue, but in a zone with zoneValue // bound to S. final f = expectLater(scheduler.schedule('c'), completion('S')); - completers['a'].complete(); - completers['b'].complete(); + completers['a']!.complete(); + completers['b']!.complete(); expect(await scheduler.schedule('a'), 'A'); expect(await scheduler.schedule('b'), 'B'); - completers['c'].complete(); + completers['c']!.complete(); await f; }, zoneValues: {'zoneValue': 'S'}); });
diff --git a/test/real_version_test.dart b/test/real_version_test.dart index 484a7f6..80afab7 100644 --- a/test/real_version_test.dart +++ b/test/real_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io'; import 'package:path/path.dart' as path;
diff --git a/test/reformat_ranges_test.dart b/test/reformat_ranges_test.dart new file mode 100644 index 0000000..35b085f --- /dev/null +++ b/test/reformat_ranges_test.dart
@@ -0,0 +1,55 @@ +// Copyright (c) 2021, 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 'package:pub/src/package_name.dart'; +import 'package:pub/src/solver/reformat_ranges.dart'; +import 'package:pub/src/utils.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +void main() { + test('reformatMax when max has a build identifier', () { + expect( + reformatMax( + [PackageId('abc', null, Version.parse('1.2.3'), null)], + VersionRange( + min: Version.parse('0.2.4'), + max: Version.parse('1.2.4'), + alwaysIncludeMaxPreRelease: true, + ), + ), + equals( + Pair( + Version.parse('1.2.4-0'), + false, + ), + ), + ); + expect( + reformatMax( + [PackageId('abc', null, Version.parse('1.2.4-3'), null)], + VersionRange( + min: Version.parse('0.2.4'), + max: Version.parse('1.2.4'), + alwaysIncludeMaxPreRelease: true, + ), + ), + equals( + Pair( + Version.parse('1.2.4-3'), + true, + ), + ), + ); + expect( + reformatMax( + [], + VersionRange( + max: Version.parse('1.2.4+1'), + alwaysIncludeMaxPreRelease: true, + ), + ), + equals(null)); + }); +}
diff --git a/test/remove/remove_test.dart b/test/remove/remove_test.dart index 777d41b..8c82527 100644 --- a/test/remove/remove_test.dart +++ b/test/remove/remove_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:io' show File; import 'package:path/path.dart' as p; @@ -14,7 +12,8 @@ void main() { test('removes a package from dependencies', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); @@ -22,17 +21,16 @@ await pubRemove(args: ['foo']); await d.cacheDir({}).validate(); - await d.appPackagesFile({}).validate(); + await d.appPackageConfigFile([]).validate(); await d.appDir().validate(); }); test('removing a package from dependencies does not affect dev_dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('foo', '1.2.2'); - builder.serve('bar', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('foo', '1.2.2') + ..serve('bar', '2.0.0'); await d.dir(appPath, [ d.file('pubspec.yaml', ''' @@ -51,7 +49,9 @@ await pubRemove(args: ['foo']); await d.cacheDir({'bar': '2.0.0'}).validate(); - await d.appPackagesFile({'bar': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'bar', version: '2.0.0'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -62,7 +62,8 @@ }); test('dry-run does not actually remove dependency', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.appDir({'foo': '1.2.3'}).create(); await pubGet(); @@ -100,7 +101,8 @@ }); test('removes a package from dev_dependencies', () async { - await servePackages((builder) => builder.serve('foo', '1.2.3')); + final server = await servePackages(); + server.serve('foo', '1.2.3'); await d.dir(appPath, [ d.pubspec({ @@ -113,7 +115,7 @@ await pubRemove(args: ['foo']); await d.cacheDir({}).validate(); - await d.appPackagesFile({}).validate(); + await d.appPackageConfigFile([]).validate(); await d.dir(appPath, [ d.pubspec({'name': 'myapp'}) @@ -122,12 +124,11 @@ test('removes multiple packages from dependencies and dev_dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3'); - builder.serve('bar', '2.3.4'); - builder.serve('baz', '3.2.1'); - builder.serve('jfj', '0.2.1'); - }); + await servePackages() + ..serve('foo', '1.2.3') + ..serve('bar', '2.3.4') + ..serve('baz', '3.2.1') + ..serve('jfj', '0.2.1'); await d.dir(appPath, [ d.pubspec({ @@ -141,7 +142,10 @@ await pubRemove(args: ['foo', 'bar', 'baz']); await d.cacheDir({'jfj': '0.2.1'}).validate(); - await d.appPackagesFile({'jfj': '0.2.1'}).validate(); + + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'jfj', version: '0.2.1'), + ]).validate(); await d.dir(appPath, [ d.pubspec({ @@ -152,7 +156,8 @@ }); test('removes git dependencies', () async { - await servePackages((builder) => builder.serve('bar', '1.2.3')); + final server = await servePackages(); + server.serve('bar', '1.2.3'); ensureGit(); final repo = d.git('foo.git', [ @@ -170,12 +175,16 @@ await pubGet(); await pubRemove(args: ['foo']); - await d.appPackagesFile({'bar': '1.2.3'}).validate(); + + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'bar', version: '1.2.3'), + ]).validate(); await d.appDir({'bar': '1.2.3'}).validate(); }); test('removes path dependencies', () async { - await servePackages((builder) => builder.serve('bar', '1.2.3')); + final server = await servePackages(); + server.serve('bar', '1.2.3'); await d .dir('foo', [d.libDir('foo'), d.libPubspec('foo', '0.0.1')]).create(); @@ -187,21 +196,23 @@ await pubGet(); await pubRemove(args: ['foo']); - await d.appPackagesFile({'bar': '1.2.3'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'bar', version: '1.2.3'), + ]).validate(); await d.appDir({'bar': '1.2.3'}).validate(); }); test('removes hosted dependencies', () async { - await servePackages((builder) => builder.serve('bar', '2.0.1')); + final server = await servePackages(); + server.serve('bar', '2.0.1'); - var server = await PackageServer.start((builder) { - builder.serve('foo', '1.2.3'); - }); + var custom = await startPackageServer(); + custom.serve('foo', '1.2.3'); await d.appDir({ 'foo': { 'version': '1.2.3', - 'hosted': {'name': 'foo', 'url': 'http://localhost:${server.port}'} + 'hosted': {'name': 'foo', 'url': 'http://localhost:${custom.port}'} }, 'bar': '2.0.1' }).create(); @@ -209,15 +220,16 @@ await pubGet(); await pubRemove(args: ['foo']); - await d.appPackagesFile({'bar': '2.0.1'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'bar', version: '2.0.1'), + ]).validate(); await d.appDir({'bar': '2.0.1'}).validate(); }); test('preserves comments', () async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - builder.serve('foo', '1.0.0'); - }); + await servePackages() + ..serve('bar', '1.0.0') + ..serve('foo', '1.0.0'); await d.dir(appPath, [ d.file('pubspec.yaml', '''
diff --git a/test/run/allows_dart_extension_test.dart b/test/run/allows_dart_extension_test.dart index f88e9bd..962270f 100644 --- a/test/run/allows_dart_extension_test.dart +++ b/test/run/allows_dart_extension_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = """ +const _script = """ import 'dart:io'; main() { @@ -23,7 +21,7 @@ test('allows a ".dart" extension on the argument', () async { await d.dir(appPath, [ d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) + d.dir('bin', [d.file('script.dart', _script)]) ]).create(); await pubGet();
diff --git a/test/run/app_can_read_from_stdin_test.dart b/test/run/app_can_read_from_stdin_test.dart index a0c3983..20f9b32 100644 --- a/test/run/app_can_read_from_stdin_test.dart +++ b/test/run/app_can_read_from_stdin_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/dartdev/app_can_read_from_stdin_test.dart b/test/run/dartdev/app_can_read_from_stdin_test.dart deleted file mode 100644 index 933b3ad..0000000 --- a/test/run/dartdev/app_can_read_from_stdin_test.dart +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('the spawned application can read line-by-line from stdin', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [ - d.file('script.dart', """ - import 'dart:io'; - - main() { - print("started"); - var line1 = stdin.readLineSync(); - print("between"); - var line2 = stdin.readLineSync(); - print(line1); - print(line2); - } - """) - ]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['myapp:script']); - - await expectLater(pub.stdout, emitsThrough('started')); - pub.stdin.writeln('first'); - await expectLater(pub.stdout, emits('between')); - pub.stdin.writeln('second'); - expect(pub.stdout, emits('first')); - expect(pub.stdout, emits('second')); - await pub.shouldExit(0); - }); - - test('the spawned application can read streamed from stdin', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [ - d.file('script.dart', """ - import 'dart:io'; - - main() { - print("started"); - stdin.listen(stdout.add); - } - """) - ]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['myapp:script']); - - await expectLater(pub.stdout, emitsThrough('started')); - pub.stdin.writeln('first'); - await expectLater(pub.stdout, emits('first')); - pub.stdin.writeln('second'); - await expectLater(pub.stdout, emits('second')); - pub.stdin.writeln('third'); - await expectLater(pub.stdout, emits('third')); - await pub.stdin.close(); - await pub.shouldExit(0); - }); -}
diff --git a/test/run/dartdev/errors_if_only_transitive_dependency_test.dart b/test/run/dartdev/errors_if_only_transitive_dependency_test.dart deleted file mode 100644 index 529eeb2..0000000 --- a/test/run/dartdev/errors_if_only_transitive_dependency_test.dart +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:pub/src/exit_codes.dart' as exit_codes; -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('Errors if the script is in a non-immediate dependency.', () async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) - ]).create(); - - await d.dir('bar', [ - d.libPubspec('bar', '1.0.0', deps: { - 'foo': {'path': '../foo'} - }) - ]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'bar': {'path': '../bar'} - }) - ]).create(); - - await pubGet(); - - var pub = await pubRunFromDartDev(args: ['foo:script']); - expect(pub.stderr, emits('Package "foo" is not an immediate dependency.')); - expect(pub.stderr, - emits('Cannot run executables in transitive dependencies.')); - await pub.shouldExit(exit_codes.DATA); - }); -}
diff --git a/test/run/dartdev/errors_if_path_in_dependency_test.dart b/test/run/dartdev/errors_if_path_in_dependency_test.dart deleted file mode 100644 index ddf553a..0000000 --- a/test/run/dartdev/errors_if_path_in_dependency_test.dart +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:pub/src/exit_codes.dart' as exit_codes; -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test( - 'Errors if the executable is in a subdirectory in a ' - 'dependency.', () async { - await d.dir('foo', [d.libPubspec('foo', '1.0.0')]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - - await runPub(args: ['run', 'foo:sub/dir'], error: ''' -Cannot run an executable in a subdirectory of a dependency. - -Usage: pub run <executable> [arguments...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. - (Will disable snapshotting, resulting in - slower startup). - --[no-]sound-null-safety Override the default null safety - execution mode. --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation. -''', exitCode: exit_codes.USAGE); - }); -}
diff --git a/test/run/dartdev/forwards_signal_posix_test.dart b/test/run/dartdev/forwards_signal_posix_test.dart deleted file mode 100644 index 6044de6..0000000 --- a/test/run/dartdev/forwards_signal_posix_test.dart +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -// Windows doesn't support sending signals. -@TestOn('!windows') -import 'dart:io'; - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -const _catchableSignals = [ - ProcessSignal.sighup, - ProcessSignal.sigterm, - ProcessSignal.sigusr1, - ProcessSignal.sigusr2, - ProcessSignal.sigwinch, -]; - -const SCRIPT = """ -import 'dart:io'; - -main() { - ProcessSignal.SIGHUP.watch().first.then(print); - ProcessSignal.SIGTERM.watch().first.then(print); - ProcessSignal.SIGUSR1.watch().first.then(print); - ProcessSignal.SIGUSR2.watch().first.then(print); - ProcessSignal.SIGWINCH.watch().first.then(print); - - print("ready"); -} -"""; - -void main() { - test('forwards signals to the inner script', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['myapp:script']); - - await expectLater(pub.stdout, emitsThrough('ready')); - for (var signal in _catchableSignals) { - pub.signal(signal); - await expectLater(pub.stdout, emits(signal.toString())); - } - - await pub.kill(); - }); -}
diff --git a/test/run/dartdev/loads_package_imports_in_a_dependency_test.dart b/test/run/dartdev/loads_package_imports_in_a_dependency_test.dart deleted file mode 100644 index f6d84c1..0000000 --- a/test/run/dartdev/loads_package_imports_in_a_dependency_test.dart +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('loads package imports in a dependency', () async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('lib', [d.file('foo.dart', "final value = 'foobar';")]), - d.dir('bin', [ - d.file('bar.dart', ''' -import "package:foo/foo.dart"; - -main() => print(value); -''') - ]) - ]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['foo:bar']); - expect(pub.stdout, emitsThrough('foobar')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/nonexistent_dependency_test.dart b/test/run/dartdev/nonexistent_dependency_test.dart deleted file mode 100644 index 695d147..0000000 --- a/test/run/dartdev/nonexistent_dependency_test.dart +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:pub/src/exit_codes.dart' as exit_codes; -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('Errors if the script is in an unknown package.', () async { - await d.dir(appPath, [d.appPubspec()]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['foo:script']); - expect( - pub.stderr, - emits('Could not find package "foo". Did you forget to add a ' - 'dependency?')); - await pub.shouldExit(exit_codes.DATA); - }); -}
diff --git a/test/run/dartdev/nonexistent_script_in_dependency_test.dart b/test/run/dartdev/nonexistent_script_in_dependency_test.dart deleted file mode 100644 index 5cf982f..0000000 --- a/test/run/dartdev/nonexistent_script_in_dependency_test.dart +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:path/path.dart' as p; -import 'package:pub/src/exit_codes.dart' as exit_codes; -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('Errors if the script in a dependency does not exist.', () async { - await d.dir('foo', [d.libPubspec('foo', '1.0.0')]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - - await pubGet(); - - var pub = await pubRunFromDartDev(args: ['foo:script']); - expect( - pub.stderr, - emits( - "Could not find ${p.join("bin", "script.dart")} in package foo.")); - await pub.shouldExit(exit_codes.NO_INPUT); - }); -}
diff --git a/test/run/dartdev/package_api_test.dart b/test/run/dartdev/package_api_test.dart deleted file mode 100644 index b4c4f80..0000000 --- a/test/run/dartdev/package_api_test.dart +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -const _script = """ - import 'dart:isolate'; - - main() async { - print(await Isolate.packageRoot); - print(await Isolate.packageConfig); - print(await Isolate.resolvePackageUri( - Uri.parse('package:myapp/resource.txt'))); - print(await Isolate.resolvePackageUri( - Uri.parse('package:foo/resource.txt'))); - } -"""; - -void main() { - test('an untransformed application sees a file: package config', () async { - await d.dir('foo', [d.libPubspec('foo', '1.0.0')]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }), - d.dir('bin', [d.file('script.dart', _script)]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['myapp:script']); - - expect(pub.stdout, emitsThrough('null')); - expect( - pub.stdout, - emits(p - .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json')) - .toString())); - expect(pub.stdout, - emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString())); - expect(pub.stdout, - emits(p.toUri(p.join(d.sandbox, 'foo/lib/resource.txt')).toString())); - await pub.shouldExit(0); - }); - - test('a snapshotted application sees a file: package root', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', _script)]) - ]); - }); - - await d.dir(appPath, [ - d.appPubspec({'foo': 'any'}) - ]).create(); - - await pubGet(); - - var pub = await pubRunFromDartDev(args: ['foo:script']); - - expect(pub.stdout, emits('Building package executable...')); - expect(pub.stdout, emits('Built foo:script.')); - expect(pub.stdout, emits('null')); - expect( - pub.stdout, - emits(p - .toUri(p.join(d.sandbox, 'myapp/.dart_tool/package_config.json')) - .toString())); - expect(pub.stdout, - emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString())); - var fooResourcePath = p.join( - globalPackageServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt'); - expect(pub.stdout, emits(p.toUri(fooResourcePath).toString())); - await pub.shouldExit(0); - }); -}
diff --git a/test/run/dartdev/passes_along_arguments_test.dart b/test/run/dartdev/passes_along_arguments_test.dart deleted file mode 100644 index 00d05fc..0000000 --- a/test/run/dartdev/passes_along_arguments_test.dart +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -const SCRIPT = ''' -main(List<String> args) { - print(args.join(" ")); -} -'''; - -void main() { - test('passes arguments to the spawned script', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('args.dart', SCRIPT)]) - ]).create(); - - await pubGet(); - - // Use some args that would trip up pub's arg parser to ensure that it - // isn't trying to look at them. - var pub = await pubRunFromDartDev( - args: ['myapp:args', '--verbose', '-m', '--', 'help']); - - expect(pub.stdout, emitsThrough('--verbose -m -- help')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_default_app_without_arguments.dart b/test/run/dartdev/runs_default_app_without_arguments.dart deleted file mode 100644 index 3b9e119..0000000 --- a/test/run/dartdev/runs_default_app_without_arguments.dart +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('runs default Dart application without arguments', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('myapp.dart', "main() => print('foobar');")]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: []); - expect(pub.stdout, emits('foobar')); - await pub.shouldExit(); - }); - - test('runs main.dart Dart application without arguments', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('main.dart', "main() => print('foobar');")]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: []); - expect(pub.stdout, emits('foobar')); - await pub.shouldExit(); - }); - - test('prefers default Dart application without arguments', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [ - d.file('myapp.dart', "main() => print('foobar');"), - d.file('main.dart', "main() => print('-');"), - ]) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: []); - expect(pub.stdout, emits('foobar')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_from_a_dependency_override_after_dependency_test.dart b/test/run/dartdev/runs_from_a_dependency_override_after_dependency_test.dart deleted file mode 100644 index 9bb84d5..0000000 --- a/test/run/dartdev/runs_from_a_dependency_override_after_dependency_test.dart +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - // Regression test for issue 23113 - test('runs a named Dart application in a dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'name': 'foo', - 'version': '1.0.0' - }, contents: [ - d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) - ]); - }); - - await d.dir(appPath, [ - d.appPubspec({'foo': null}) - ]).create(); - - await pubGet(args: ['--precompile']); - - var pub = await pubRunFromDartDev(args: ['foo:bar']); - expect(pub.stdout, emitsThrough('foobar')); - await pub.shouldExit(); - - await d.dir('foo', [ - d.libPubspec('foo', '2.0.0'), - d.dir('bin', [d.file('bar.dart', "main() => print('different');")]) - ]).create(); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'dependencies': { - 'foo': {'path': '../foo'} - } - }) - ]).create(); - - await pubGet(); - - pub = await pubRunFromDartDev(args: ['foo:bar']); - expect(pub.stdout, emitsThrough('different')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_named_app_in_dependency_test.dart b/test/run/dartdev/runs_named_app_in_dependency_test.dart deleted file mode 100644 index b7e3124..0000000 --- a/test/run/dartdev/runs_named_app_in_dependency_test.dart +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('runs a named Dart application in a dependency', () async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) - ]).create(); - - await d.dir(appPath, [ - d.appPubspec({ - 'foo': {'path': '../foo'} - }) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['foo:bar']); - expect(pub.stdout, emitsThrough('foobar')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_named_app_in_dev_dependency_test.dart b/test/run/dartdev/runs_named_app_in_dev_dependency_test.dart deleted file mode 100644 index 990d360..0000000 --- a/test/run/dartdev/runs_named_app_in_dev_dependency_test.dart +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('runs a named Dart application in a dev dependency', () async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) - ]).create(); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'dev_dependencies': { - 'foo': {'path': '../foo'} - } - }) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['foo:bar']); - expect(pub.stdout, emitsThrough('foobar')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_shorthand_app_in_dependency_test.dart b/test/run/dartdev/runs_shorthand_app_in_dependency_test.dart deleted file mode 100644 index 5cf7865..0000000 --- a/test/run/dartdev/runs_shorthand_app_in_dependency_test.dart +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('runs a shorthand Dart application in a dependency', () async { - await d.dir('foo', [ - d.libPubspec('foo', '1.0.0'), - d.dir('bin', [d.file('foo.dart', "main() => print('foo');")]) - ]).create(); - - await d.dir(appPath, [ - d.pubspec({ - 'name': 'myapp', - 'dependencies': { - 'foo': {'path': '../foo'} - } - }) - ]).create(); - - await pubGet(); - var pub = await pubRunFromDartDev(args: ['foo']); - expect(pub.stdout, emitsThrough('foo')); - await pub.shouldExit(); - }); -}
diff --git a/test/run/dartdev/runs_the_script_in_checked_mode_test.dart b/test/run/dartdev/runs_the_script_in_checked_mode_test.dart deleted file mode 100644 index 002406f..0000000 --- a/test/run/dartdev/runs_the_script_in_checked_mode_test.dart +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -void main() { - test('runs the script with assertions enabled', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('script.dart', 'main() { assert(false); }')]) - ]).create(); - - await pubGet(); - await runPub( - args: ['run', '--enable-asserts', 'myapp:script'], - error: contains('Failed assertion'), - exitCode: 255); - }); -}
diff --git a/test/run/dartdev/runs_the_script_in_unchecked_mode_test.dart b/test/run/dartdev/runs_the_script_in_unchecked_mode_test.dart deleted file mode 100644 index bc85e54..0000000 --- a/test/run/dartdev/runs_the_script_in_unchecked_mode_test.dart +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart=2.10 - -import 'package:test/test.dart'; - -import '../../descriptor.dart' as d; -import '../../test_pub.dart'; - -const SCRIPT = ''' -main() { - assert(false); - print("no checks"); -} -'''; - -void main() { - test('runs the script without assertions by default', () async { - await d.dir(appPath, [ - d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) - ]).create(); - - await pubGet(); - await runPub(args: ['run', 'myapp:script'], output: contains('no checks')); - }); -}
diff --git a/test/run/enable_experiments_test.dart b/test/run/enable_experiments_test.dart index 95468f0..dd6512b 100644 --- a/test/run/enable_experiments_test.dart +++ b/test/run/enable_experiments_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/errors_if_no_executable_is_given_test.dart b/test/run/errors_if_no_executable_is_given_test.dart index 2bec1a3..3e5abd6 100644 --- a/test/run/errors_if_no_executable_is_given_test.dart +++ b/test/run/errors_if_no_executable_is_given_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -14,22 +12,10 @@ test('Errors if the executable does not exist.', () async { await d.dir(appPath, [d.appPubspec()]).create(); - await runPub(args: ['run'], error: ''' -Must specify an executable to run. - -Usage: pub run <executable> [arguments...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. - (Will disable snapshotting, resulting in - slower startup). - --[no-]sound-null-safety Override the default null safety - execution mode. --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation. -''', exitCode: exit_codes.USAGE); + await runPub( + args: ['run'], + error: contains('Must specify an executable to run.'), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/run/errors_if_only_transitive_dependency_test.dart b/test/run/errors_if_only_transitive_dependency_test.dart index d5d1601..71fcd3d 100644 --- a/test/run/errors_if_only_transitive_dependency_test.dart +++ b/test/run/errors_if_only_transitive_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/run/errors_if_path_in_dependency_test.dart b/test/run/errors_if_path_in_dependency_test.dart index 5625c4e..329650b 100644 --- a/test/run/errors_if_path_in_dependency_test.dart +++ b/test/run/errors_if_path_in_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -22,22 +20,12 @@ }) ]).create(); - await runPub(args: ['run', 'foo:sub/dir'], error: ''' -Cannot run an executable in a subdirectory of a dependency. - -Usage: pub run <executable> [arguments...] --h, --help Print this usage information. - --[no-]enable-asserts Enable assert statements. - --enable-experiment=<experiment> Runs the executable in a VM with the - given experiments enabled. - (Will disable snapshotting, resulting in - slower startup). - --[no-]sound-null-safety Override the default null safety - execution mode. --C, --directory=<dir> Run this in the directory<dir>. - -Run "pub help" to see global options. -See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation. -''', exitCode: exit_codes.USAGE); + await runPub( + args: ['run', 'foo:sub/dir'], + error: contains( + 'Cannot run an executable in a subdirectory of a dependency.', + ), + exitCode: exit_codes.USAGE, + ); }); }
diff --git a/test/run/forwards_signal_posix_test.dart b/test/run/forwards_signal_posix_test.dart index 17fb0ea..5205145 100644 --- a/test/run/forwards_signal_posix_test.dart +++ b/test/run/forwards_signal_posix_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - // Windows doesn't support sending signals. // TODO(sigurdm): Test this when vm-args are provided. // This test doesn't work when we subprocess instead of an isolate @@ -25,7 +23,7 @@ ProcessSignal.sigwinch, ]; -const SCRIPT = """ +const _script = """ import 'dart:io'; main() { @@ -43,7 +41,7 @@ test('forwards signals to the inner script', () async { await d.dir(appPath, [ d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) + d.dir('bin', [d.file('script.dart', _script)]) ]).create(); await pubGet();
diff --git a/test/run/includes_parent_directories_of_entrypoint_test.dart b/test/run/includes_parent_directories_of_entrypoint_test.dart index f17b548..6bc4e27 100644 --- a/test/run/includes_parent_directories_of_entrypoint_test.dart +++ b/test/run/includes_parent_directories_of_entrypoint_test.dart
@@ -2,15 +2,13 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = r""" +const _script = r""" import '../../a.dart'; import '../b.dart'; main() { @@ -28,7 +26,7 @@ d.file('a.dart', "var a = 'a';"), d.dir('a', [ d.file('b.dart', "var b = 'b';"), - d.dir('b', [d.file('app.dart', SCRIPT)]) + d.dir('b', [d.file('app.dart', _script)]) ]) ]) ]).create();
diff --git a/test/run/loads_package_imports_in_a_dependency_test.dart b/test/run/loads_package_imports_in_a_dependency_test.dart index 66c261d..7bfb047 100644 --- a/test/run/loads_package_imports_in_a_dependency_test.dart +++ b/test/run/loads_package_imports_in_a_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/nonexistent_dependency_test.dart b/test/run/nonexistent_dependency_test.dart index 5b0f941..2051149 100644 --- a/test/run/nonexistent_dependency_test.dart +++ b/test/run/nonexistent_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/run/nonexistent_script_in_dependency_test.dart b/test/run/nonexistent_script_in_dependency_test.dart index 5153c25..62816df 100644 --- a/test/run/nonexistent_script_in_dependency_test.dart +++ b/test/run/nonexistent_script_in_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/run/nonexistent_script_test.dart b/test/run/nonexistent_script_test.dart index 9930430..0e12ee1 100644 --- a/test/run/nonexistent_script_test.dart +++ b/test/run/nonexistent_script_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/run/package_api_test.dart b/test/run/package_api_test.dart index e7b814f..4d05408 100644 --- a/test/run/package_api_test.dart +++ b/test/run/package_api_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -51,11 +49,10 @@ }); test('a snapshotted application sees a file: package root', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', contents: [ - d.dir('bin', [d.file('script.dart', _script)]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', contents: [ + d.dir('bin', [d.file('script.dart', _script)]) + ]); await d.dir(appPath, [ d.appPubspec({'foo': 'any'}) @@ -75,8 +72,8 @@ .toString())); expect(pub.stdout, emits(p.toUri(p.join(d.sandbox, 'myapp/lib/resource.txt')).toString())); - var fooResourcePath = p.join( - globalPackageServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt'); + var fooResourcePath = + p.join(globalServer.pathInCache('foo', '1.0.0'), 'lib/resource.txt'); expect(pub.stdout, emits(p.toUri(fooResourcePath).toString())); await pub.shouldExit(0); });
diff --git a/test/run/passes_along_arguments_test.dart b/test/run/passes_along_arguments_test.dart index d2beebf..624d9f2 100644 --- a/test/run/passes_along_arguments_test.dart +++ b/test/run/passes_along_arguments_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = ''' +const _script = ''' main(List<String> args) { print(args.join(" ")); } @@ -19,7 +17,7 @@ test('passes arguments to the spawned script', () async { await d.dir(appPath, [ d.appPubspec(), - d.dir('bin', [d.file('args.dart', SCRIPT)]) + d.dir('bin', [d.file('args.dart', _script)]) ]).create(); await pubGet();
diff --git a/test/run/precompile_test.dart b/test/run/precompile_test.dart index ac663d5..2d70b4c 100644 --- a/test/run/precompile_test.dart +++ b/test/run/precompile_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = r''' +const _script = r''' import 'dart:io'; main(List<String> args) { @@ -23,11 +21,11 @@ d.appPubspec({'test': '1.0.0'}), ]).create(); - await servePackages((server) => server - ..serve('test', '1.0.0', contents: [ - d.dir('bin', - [d.file('test.dart', 'main(List<String> args) => print("hello");')]) - ])); + final server = await servePackages(); + server.serve('test', '1.0.0', contents: [ + d.dir('bin', + [d.file('test.dart', 'main(List<String> args) => print("hello");')]) + ]); await pubGet(args: ['--no-precompile']); } @@ -59,10 +57,10 @@ d.appPubspec({'test': '1.0.0'}), ]).create(); - await servePackages((server) => server - ..serve('test', '1.0.0', contents: [ - d.dir('bin', [d.file('test.dart', SCRIPT)]) - ])); + final server = await servePackages(); + server.serve('test', '1.0.0', contents: [ + d.dir('bin', [d.file('test.dart', _script)]) + ]); await pubGet( args: ['--no-precompile'], environment: {'PUB_CACHE': '.pub_cache'}); @@ -82,10 +80,10 @@ d.appPubspec({'test': '1.0.0'}), ]).create(); - await servePackages((server) => server - ..serve('test', '1.0.0', contents: [ - d.dir('bin', [d.file('test.dart', SCRIPT)]) - ])); + final server = await servePackages(); + server.serve('test', '1.0.0', contents: [ + d.dir('bin', [d.file('test.dart', _script)]) + ]); await pubGet( args: ['--precompile'], @@ -106,10 +104,10 @@ d.appPubspec({'test': '1.0.0'}), ]).create(); - await servePackages((server) => server - ..serve('test', '1.0.0', contents: [ - d.dir('bin', [d.file('test.dart', SCRIPT)]) - ])); + final server = await servePackages(); + server.serve('test', '1.0.0', contents: [ + d.dir('bin', [d.file('test.dart', _script)]) + ]); await pubGet( args: ['--precompile'],
diff --git a/test/run/runs_app_in_directory_in_entrypoint_test.dart b/test/run/runs_app_in_directory_in_entrypoint_test.dart index ef720c5..ac8af0d 100644 --- a/test/run/runs_app_in_directory_in_entrypoint_test.dart +++ b/test/run/runs_app_in_directory_in_entrypoint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:test/test.dart';
diff --git a/test/run/runs_app_in_entrypoint_test.dart b/test/run/runs_app_in_entrypoint_test.dart index 3f3ed38..6cb932a 100644 --- a/test/run/runs_app_in_entrypoint_test.dart +++ b/test/run/runs_app_in_entrypoint_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = """ +const _script = """ import 'dart:io'; main() { @@ -23,7 +21,7 @@ test('runs a Dart application in the entrypoint package', () async { await d.dir(appPath, [ d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) + d.dir('bin', [d.file('script.dart', _script)]) ]).create(); await pubGet();
diff --git a/test/run/runs_from_a_dependency_override_after_dependency_test.dart b/test/run/runs_from_a_dependency_override_after_dependency_test.dart index c3cde77..c11bacb 100644 --- a/test/run/runs_from_a_dependency_override_after_dependency_test.dart +++ b/test/run/runs_from_a_dependency_override_after_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -12,14 +10,13 @@ void main() { // Regression test for issue 23113 test('runs a named Dart application in a dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'name': 'foo', - 'version': '1.0.0' - }, contents: [ - d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'name': 'foo', + 'version': '1.0.0' + }, contents: [ + d.dir('bin', [d.file('bar.dart', "main() => print('foobar');")]) + ]); await d.dir(appPath, [ d.appPubspec({'foo': null})
diff --git a/test/run/runs_named_app_in_dependency_test.dart b/test/run/runs_named_app_in_dependency_test.dart index d554eb4..8f3d73d 100644 --- a/test/run/runs_named_app_in_dependency_test.dart +++ b/test/run/runs_named_app_in_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/runs_named_app_in_dev_dependency_test.dart b/test/run/runs_named_app_in_dev_dependency_test.dart index f1493d4..287f05b 100644 --- a/test/run/runs_named_app_in_dev_dependency_test.dart +++ b/test/run/runs_named_app_in_dev_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/runs_shorthand_app_in_dependency_test.dart b/test/run/runs_shorthand_app_in_dependency_test.dart index cd3c66a..455e049 100644 --- a/test/run/runs_shorthand_app_in_dependency_test.dart +++ b/test/run/runs_shorthand_app_in_dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/runs_the_script_in_checked_mode_test.dart b/test/run/runs_the_script_in_checked_mode_test.dart index 8b8e214..8b4010a 100644 --- a/test/run/runs_the_script_in_checked_mode_test.dart +++ b/test/run/runs_the_script_in_checked_mode_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d;
diff --git a/test/run/runs_the_script_in_unchecked_mode_test.dart b/test/run/runs_the_script_in_unchecked_mode_test.dart index da86989..026a748 100644 --- a/test/run/runs_the_script_in_unchecked_mode_test.dart +++ b/test/run/runs_the_script_in_unchecked_mode_test.dart
@@ -2,14 +2,12 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -const SCRIPT = ''' +const _script = ''' main() { assert(false); print("no checks"); @@ -20,7 +18,7 @@ test('runs the script without assertions by default', () async { await d.dir(appPath, [ d.appPubspec(), - d.dir('bin', [d.file('script.dart', SCRIPT)]) + d.dir('bin', [d.file('script.dart', _script)]) ]).create(); await pubGet();
diff --git a/test/sdk_test.dart b/test/sdk_test.dart index 93ebdac..6165cd5 100644 --- a/test/sdk_test.dart +++ b/test/sdk_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/io.dart'; @@ -15,9 +13,8 @@ void main() { forBothPubGetAndUpgrade((command) { setUp(() async { - await servePackages((builder) { - builder.serve('bar', '1.0.0'); - }); + final server = await servePackages(); + server.serve('bar', '1.0.0'); await d.dir('flutter', [ d.dir('packages', [ @@ -40,13 +37,10 @@ }).create(); await pubCommand(command, environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')}); - - await d.dir(appPath, [ - d.packagesFile({ - 'myapp': '.', - 'foo': p.join(d.sandbox, 'flutter', 'packages', 'foo'), - 'bar': '1.0.0' - }) + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'foo', path: p.join(d.sandbox, 'flutter', 'packages', 'foo')), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), ]).validate(); }); @@ -57,11 +51,10 @@ await pubCommand(command, environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')}); - await d.dir(appPath, [ - d.packagesFile({ - 'myapp': '.', - 'baz': p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz') - }) + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'baz', + path: p.join(d.sandbox, 'flutter', 'bin', 'cache', 'pkg', 'baz')), ]).validate(); }); @@ -96,10 +89,7 @@ deleteEntry(p.join(d.sandbox, 'flutter', 'version')); await pubCommand(command, environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')}); - - await d.dir(appPath, [ - d.packagesFile({'myapp': '.'}) - ]).validate(); + await d.appPackageConfigFile([]).validate(); }); group('fails if', () { @@ -120,7 +110,7 @@ 'foo': {'sdk': 'unknown'} }).create(); await pubCommand(command, error: equalsIgnoringWhitespace(""" - Because myapp depends on foo any from sdk which doesn't exist + Because myapp depends on foo from sdk which doesn't exist (unknown SDK "unknown"), version solving failed. """), exitCode: exit_codes.UNAVAILABLE); }); @@ -130,7 +120,7 @@ 'foo': {'sdk': 'flutter'} }).create(); await pubCommand(command, error: equalsIgnoringWhitespace(""" - Because myapp depends on foo any from sdk which doesn't exist (the + Because myapp depends on foo from sdk which doesn't exist (the Flutter SDK is not available), version solving failed. Flutter users should run `flutter pub get` instead of `dart pub @@ -145,7 +135,7 @@ await pubCommand(command, environment: {'FLUTTER_ROOT': p.join(d.sandbox, 'flutter')}, error: equalsIgnoringWhitespace(""" - Because myapp depends on bar any from sdk which doesn't exist + Because myapp depends on bar from sdk which doesn't exist (could not find package bar in the Flutter SDK), version solving failed. """), @@ -157,7 +147,7 @@ 'bar': {'sdk': 'dart'} }).create(); await pubCommand(command, error: equalsIgnoringWhitespace(""" - Because myapp depends on bar any from sdk which doesn't exist + Because myapp depends on bar from sdk which doesn't exist (could not find package bar in the Dart SDK), version solving failed. """), exitCode: exit_codes.UNAVAILABLE); @@ -172,13 +162,10 @@ }).create(); await pubCommand(command, environment: {'FUCHSIA_DART_SDK_ROOT': p.join(d.sandbox, 'fuchsia')}); - - await d.dir(appPath, [ - d.packagesFile({ - 'myapp': '.', - 'foo': p.join(d.sandbox, 'fuchsia', 'packages', 'foo'), - 'bar': '1.0.0' - }) + await d.appPackageConfigFile([ + d.packageConfigEntry( + name: 'foo', path: p.join(d.sandbox, 'fuchsia', 'packages', 'foo')), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), ]).validate(); }); });
diff --git a/test/snapshot_test.dart b/test/snapshot_test.dart index 6ad44f6..8143f7e 100644 --- a/test/snapshot_test.dart +++ b/test/snapshot_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -13,17 +11,15 @@ void main() { group('creates a snapshot', () { test('for an immediate dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', contents: [ - d.dir('bin', [ - d.file('hello.dart', "void main() => print('hello!');"), - d.file('goodbye.dart', "void main() => print('goodbye!');"), - d.file('shell.sh', 'echo shell'), - d.dir( - 'subdir', [d.file('sub.dart', "void main() => print('sub!');")]) - ]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3', contents: [ + d.dir('bin', [ + d.file('hello.dart', "void main() => print('hello!');"), + d.file('goodbye.dart', "void main() => print('goodbye!');"), + d.file('shell.sh', 'echo shell'), + d.dir('subdir', [d.file('sub.dart', "void main() => print('sub!');")]) + ]) + ]); await d.appDir({'foo': '1.2.3'}).create(); @@ -51,8 +47,8 @@ }); test("for an immediate dependency that's also transitive", () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', contents: [ + await servePackages() + ..serve('foo', '1.2.3', contents: [ d.dir('bin', [ d.file('hello.dart', "void main() => print('hello!');"), d.file('goodbye.dart', "void main() => print('goodbye!');"), @@ -60,9 +56,8 @@ d.dir( 'subdir', [d.file('sub.dart', "void main() => print('sub!');")]) ]) - ]); - builder.serve('bar', '1.2.3', deps: {'foo': '1.2.3'}); - }); + ]) + ..serve('bar', '1.2.3', deps: {'foo': '1.2.3'}); await d.appDir({'foo': '1.2.3'}).create(); @@ -91,12 +86,11 @@ group('again if', () { test('its package is updated', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', contents: [ - d.dir('bin', - [d.file('hello.dart', "void main() => print('hello!');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '1.2.3', contents: [ + d.dir( + 'bin', [d.file('hello.dart', "void main() => print('hello!');")]) + ]); await d.appDir({'foo': 'any'}).create(); @@ -107,12 +101,10 @@ d.file('hello.dart-$versionSuffix.snapshot', contains('hello!')) ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '1.2.4', contents: [ - d.dir('bin', - [d.file('hello.dart', "void main() => print('hello 2!');")]) - ]); - }); + server.serve('foo', '1.2.4', contents: [ + d.dir('bin', + [d.file('hello.dart', "void main() => print('hello 2!');")]) + ]); await pubUpgrade( args: ['--precompile'], output: contains('Built foo:hello.')); @@ -127,22 +119,22 @@ }); test('a dependency of its package is updated', () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', pubspec: { - 'dependencies': {'bar': 'any'} - }, contents: [ - d.dir('bin', [ - d.file('hello.dart', """ + final server = await servePackages(); + + server.serve('foo', '1.2.3', pubspec: { + 'dependencies': {'bar': 'any'} + }, contents: [ + d.dir('bin', [ + d.file('hello.dart', """ import 'package:bar/bar.dart'; void main() => print(message); """) - ]) - ]); - builder.serve('bar', '1.2.3', contents: [ - d.dir('lib', [d.file('bar.dart', "final message = 'hello!';")]) - ]); - }); + ]) + ]); + server.serve('bar', '1.2.3', contents: [ + d.dir('lib', [d.file('bar.dart', "final message = 'hello!';")]) + ]); await d.appDir({'foo': 'any'}).create(); @@ -153,11 +145,9 @@ d.file('hello.dart-$versionSuffix.snapshot', contains('hello!')) ]).validate(); - globalPackageServer.add((builder) { - builder.serve('bar', '1.2.4', contents: [ - d.dir('lib', [d.file('bar.dart', "final message = 'hello 2!';")]), - ]); - }); + server.serve('bar', '1.2.4', contents: [ + d.dir('lib', [d.file('bar.dart', "final message = 'hello 2!';")]), + ]); await pubUpgrade( args: ['--precompile'], output: contains('Built foo:hello.')); @@ -209,12 +199,11 @@ }); test('the SDK is out of date', () async { - await servePackages((builder) { - builder.serve('foo', '5.6.7', contents: [ - d.dir('bin', - [d.file('hello.dart', "void main() => print('hello!');")]) - ]); - }); + final server = await servePackages(); + server.serve('foo', '5.6.7', contents: [ + d.dir( + 'bin', [d.file('hello.dart', "void main() => print('hello!');")]) + ]); await d.appDir({'foo': '5.6.7'}).create();
diff --git a/test/test_pub.dart b/test/test_pub.dart index 1351914..be2825e 100644 --- a/test/test_pub.dart +++ b/test/test_pub.dart
@@ -2,15 +2,13 @@ // 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. -// @dart=2.10 - /// Test infrastructure for testing pub. /// /// Unlike typical unit tests, most pub tests are integration tests that stage /// some stuff on the file system, run pub, and then validate the results. This /// library provides an API to build tests like that. -import 'dart:async'; import 'dart:convert'; +import 'dart:core'; import 'dart:io'; import 'dart:isolate'; import 'dart:math'; @@ -28,7 +26,6 @@ import 'package:pub/src/io.dart'; import 'package:pub/src/lock_file.dart'; import 'package:pub/src/log.dart' as log; -import 'package:pub/src/sdk.dart'; import 'package:pub/src/source_registry.dart'; import 'package:pub/src/system_cache.dart'; import 'package:pub/src/utils.dart'; @@ -39,11 +36,9 @@ import 'package:test_process/test_process.dart'; import 'descriptor.dart' as d; -import 'descriptor_server.dart'; import 'package_server.dart'; -export 'descriptor_server.dart'; -export 'package_server.dart'; +export 'package_server.dart' show PackageServer; /// A [Matcher] that matches JavaScript generated by dart2js with minification /// enabled. @@ -82,7 +77,7 @@ orElse: () => null) as Map<String, dynamic>; /// The suffix appended to a built snapshot. -final versionSuffix = testVersion ?? sdk.version; +final versionSuffix = testVersion; /// Enum identifying a pub command that can be run with a well-defined success /// output. @@ -130,14 +125,15 @@ // TODO(rnystrom): Clean up other tests to call this when possible. Future<void> pubCommand( RunCommand command, { - Iterable<String> args, - output, - error, - silent, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory, + Iterable<String>? args, + Object? output, + Object? error, + Object? silent, + Object? warning, + int? exitCode, + Map<String, String?>? environment, + String? workingDirectory, + includeParentEnvironment = true, }) async { if (error != null && warning != null) { throw ArgumentError("Cannot pass both 'error' and 'warning'."); @@ -161,17 +157,18 @@ silent: silent, exitCode: exitCode, environment: environment, - workingDirectory: workingDirectory); + workingDirectory: workingDirectory, + includeParentEnvironment: includeParentEnvironment); } Future<void> pubAdd({ - Iterable<String> args, - output, - error, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory, + Iterable<String>? args, + Object? output, + Object? error, + Object? warning, + int? exitCode, + Map<String, String>? environment, + String? workingDirectory, }) async => await pubCommand( RunCommand.add, @@ -185,13 +182,14 @@ ); Future<void> pubGet({ - Iterable<String> args, - output, - error, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory, + Iterable<String>? args, + Object? output, + Object? error, + Object? warning, + int? exitCode, + Map<String, String?>? environment, + String? workingDirectory, + bool includeParentEnvironment = true, }) async => await pubCommand( RunCommand.get, @@ -202,16 +200,17 @@ exitCode: exitCode, environment: environment, workingDirectory: workingDirectory, + includeParentEnvironment: includeParentEnvironment, ); Future<void> pubUpgrade( - {Iterable<String> args, - output, - error, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory}) async => + {Iterable<String>? args, + Object? output, + Object? error, + Object? warning, + int? exitCode, + Map<String, String>? environment, + String? workingDirectory}) async => await pubCommand( RunCommand.upgrade, args: args, @@ -224,13 +223,13 @@ ); Future<void> pubDowngrade({ - Iterable<String> args, - output, - error, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory, + Iterable<String>? args, + Object? output, + Object? error, + Object? warning, + int? exitCode, + Map<String, String>? environment, + String? workingDirectory, }) async => await pubCommand( RunCommand.downgrade, @@ -244,13 +243,13 @@ ); Future<void> pubRemove({ - Iterable<String> args, - output, - error, - warning, - int exitCode, - Map<String, String> environment, - String workingDirectory, + Iterable<String>? args, + Object? output, + Object? error, + Object? warning, + int? exitCode, + Map<String, String>? environment, + String? workingDirectory, }) async => await pubCommand( RunCommand.remove, @@ -272,8 +271,8 @@ /// Returns the `pub run` process. Future<PubProcess> pubRun( {bool global = false, - Iterable<String> args, - Map<String, String> environment, + required Iterable<String> args, + Map<String, String>? environment, bool verbose = true}) async { var pubArgs = global ? ['global', 'run'] : ['run']; pubArgs.addAll(args); @@ -290,20 +289,6 @@ return pub; } -/// Schedules starting the "pub run --v2" process and validates the -/// expected startup output. -/// -/// Returns the `pub run` process. -Future<PubProcess> pubRunFromDartDev({Iterable<String> args}) async { - final pub = await startPub(args: ['run', '--dart-dev-run', ...args]); - - // Loading sources and transformers isn't normally printed, but the pub test - // infrastructure runs pub in verbose mode, which enables this. - expect(pub.stdout, mayEmitMultiple(startsWith('Loading'))); - - return pub; -} - /// Schedules renaming (moving) the directory at [from] to [to], both of which /// are assumed to be relative to [d.sandbox]. void renameInSandbox(String from, String to) { @@ -330,23 +315,27 @@ /// /// If [environment] is given, any keys in it will override the environment /// variables passed to the spawned process. -Future<void> runPub({ - List<String> args, - output, - error, - outputJson, - silent, - int exitCode, - String workingDirectory, - Map<String, String> environment, - List<String> input, -}) async { +Future<void> runPub( + {List<String>? args, + Object? output, + Object? error, + Object? outputJson, + Object? silent, + int? exitCode, + String? workingDirectory, + Map<String, String?>? environment, + List<String>? input, + includeParentEnvironment = true}) async { exitCode ??= exit_codes.SUCCESS; // Cannot pass both output and outputJson. assert(output == null || outputJson == null); var pub = await startPub( - args: args, workingDirectory: workingDirectory, environment: environment); + args: args, + workingDirectory: workingDirectory, + environment: environment, + includeParentEnvironment: includeParentEnvironment, + ); if (input != null) { input.forEach(pub.stdin.writeln); @@ -379,14 +368,20 @@ /// package server. /// /// Any futures in [args] will be resolved before the process is started. -Future<PubProcess> startPublish(PackageServer server, - {List<String> args}) async { +Future<PubProcess> startPublish( + PackageServer server, { + List<String>? args, + String authMethod = 'oauth2', + Map<String, String>? environment, + String path = '', +}) async { var tokenEndpoint = Uri.parse(server.url).resolve('/token').toString(); args = ['lish', ...?args]; - return await startPub( - args: args, - tokenEndpoint: tokenEndpoint, - environment: {'PUB_HOSTED_URL': server.url}); + return await startPub(args: args, tokenEndpoint: tokenEndpoint, environment: { + 'PUB_HOSTED_URL': server.url + path, + '_PUB_TEST_AUTH_METHOD': authMethod, + if (environment != null) ...environment, + }); } /// Handles the beginning confirmation process for uploading a packages. @@ -416,28 +411,19 @@ String testVersion = '0.1.2+3'; /// Gets the environment variables used to run pub in a test context. -Map<String, String> getPubTestEnvironment([String tokenEndpoint]) { - var environment = { - 'CI': 'false', // unless explicitly given tests don't run pub in CI mode - '_PUB_TESTING': 'true', - '_PUB_TEST_CONFIG_DIR': _pathInSandbox(configPath), - 'PUB_CACHE': _pathInSandbox(cachePath), - 'PUB_ENVIRONMENT': 'test-environment', +Map<String, String> getPubTestEnvironment([String? tokenEndpoint]) => { + 'CI': 'false', // unless explicitly given tests don't run pub in CI mode + '_PUB_TESTING': 'true', + '_PUB_TEST_CONFIG_DIR': _pathInSandbox(configPath), + 'PUB_CACHE': _pathInSandbox(cachePath), + 'PUB_ENVIRONMENT': 'test-environment', - // Ensure a known SDK version is set for the tests that rely on that. - '_PUB_TEST_SDK_VERSION': testVersion - }; - - if (tokenEndpoint != null) { - environment['_PUB_TEST_TOKEN_ENDPOINT'] = tokenEndpoint; - } - - if (globalServer != null) { - environment['PUB_HOSTED_URL'] = 'http://localhost:${globalServer.port}'; - } - - return environment; -} + // Ensure a known SDK version is set for the tests that rely on that. + '_PUB_TEST_SDK_VERSION': testVersion, + if (tokenEndpoint != null) '_PUB_TEST_TOKEN_ENDPOINT': tokenEndpoint, + if (_globalServer?.port != null) + 'PUB_HOSTED_URL': 'http://localhost:${_globalServer?.port}' + }; /// The path to the root of pub's sources in the pub repo. final String _pubRoot = (() { @@ -456,25 +442,16 @@ /// If [environment] is given, any keys in it will override the environment /// variables passed to the spawned process. Future<PubProcess> startPub( - {Iterable<String> args, - String tokenEndpoint, - String workingDirectory, - Map<String, String> environment, - bool verbose = true}) async { + {Iterable<String>? args, + String? tokenEndpoint, + String? workingDirectory, + Map<String, String?>? environment, + bool verbose = true, + includeParentEnvironment = true}) async { args ??= []; ensureDir(_pathInSandbox(appPath)); - // Find a Dart executable we can use to spawn. Use the same one that was - // used to run this script itself. - var dartBin = Platform.executable; - - // If the executable looks like a path, get its full path. That way we - // can still find it when we spawn it with a different working directory. - if (dartBin.contains(Platform.pathSeparator)) { - dartBin = p.absolute(dartBin); - } - // If there's a snapshot for "pub" available we use it. If the snapshot is // out-of-date local source the tests will be useless, therefore it is // recommended to use a temporary file with a unique name for each test run. @@ -489,37 +466,47 @@ var dartArgs = ['--packages=$dotPackagesPath', '--enable-asserts']; dartArgs - ..addAll([pubPath, if (verbose) '--verbose']) + ..addAll([pubPath, if (!verbose) '--verbosity=normal']) ..addAll(args); - return await PubProcess.start(dartBin, dartArgs, - environment: getPubTestEnvironment(tokenEndpoint) - ..addAll(environment ?? {}), + final mergedEnvironment = getPubTestEnvironment(tokenEndpoint); + for (final e in (environment ?? {}).entries) { + var value = e.value; + if (value == null) { + mergedEnvironment.remove(e.key); + } else { + mergedEnvironment[e.key] = value; + } + } + + return await PubProcess.start(Platform.resolvedExecutable, dartArgs, + environment: mergedEnvironment, workingDirectory: workingDirectory ?? _pathInSandbox(appPath), - description: args.isEmpty ? 'pub' : 'pub ${args.first}'); + description: args.isEmpty ? 'pub' : 'pub ${args.first}', + includeParentEnvironment: includeParentEnvironment); } /// A subclass of [TestProcess] that parses pub's verbose logging output and /// makes [stdout] and [stderr] work as though pub weren't running in verbose /// mode. class PubProcess extends TestProcess { - StreamSplitter<Pair<log.Level, String>> get _logSplitter { - __logSplitter ??= StreamSplitter(StreamGroup.merge([ - _outputToLog(super.stdoutStream(), log.Level.MESSAGE), - _outputToLog(super.stderrStream(), log.Level.ERROR) + late final StreamSplitter<Pair<log.Level, String>> _logSplitter = + createLogSplitter(); + + StreamSplitter<Pair<log.Level, String>> createLogSplitter() { + return StreamSplitter(StreamGroup.merge([ + _outputToLog(super.stdoutStream(), log.Level.message), + _outputToLog(super.stderrStream(), log.Level.error) ])); - return __logSplitter; } - StreamSplitter<Pair<log.Level, String>> __logSplitter; - static Future<PubProcess> start(String executable, Iterable<String> arguments, - {String workingDirectory, - Map<String, String> environment, + {String? workingDirectory, + Map<String, String>? environment, bool includeParentEnvironment = true, bool runInShell = false, - String description, - Encoding encoding, + String? description, + Encoding encoding = utf8, bool forwardStdio = false}) async { var process = await Process.start(executable, arguments.toList(), workingDirectory: workingDirectory, @@ -534,25 +521,24 @@ description = '$humanExecutable ${arguments.join(' ')}'; } - encoding ??= utf8; return PubProcess(process, description, encoding: encoding, forwardStdio: forwardStdio); } /// This is protected. PubProcess(process, description, - {Encoding encoding, bool forwardStdio = false}) + {Encoding encoding = utf8, bool forwardStdio = false}) : super(process, description, encoding: encoding, forwardStdio: forwardStdio); final _logLineRegExp = RegExp(r'^([A-Z ]{4})[:|] (.*)$'); final Map<String, log.Level> _logLevels = [ - log.Level.ERROR, - log.Level.WARNING, - log.Level.MESSAGE, - log.Level.IO, - log.Level.SOLVER, - log.Level.FINE + log.Level.error, + log.Level.warning, + log.Level.message, + log.Level.io, + log.Level.solver, + log.Level.fine ].fold({}, (levels, level) { levels[level.name] = level; return levels; @@ -560,21 +546,21 @@ Stream<Pair<log.Level, String>> _outputToLog( Stream<String> stream, log.Level defaultLevel) { - log.Level lastLevel; + late log.Level lastLevel; return stream.map((line) { var match = _logLineRegExp.firstMatch(line); if (match == null) return Pair<log.Level, String>(defaultLevel, line); var level = _logLevels[match[1]] ?? lastLevel; lastLevel = level; - return Pair<log.Level, String>(level, match[2]); + return Pair<log.Level, String>(level, match[2]!); }); } @override Stream<String> stdoutStream() { return _logSplitter.split().expand((entry) { - if (entry.first != log.Level.MESSAGE) return []; + if (entry.first != log.Level.message) return []; return [entry.last]; }); } @@ -582,7 +568,7 @@ @override Stream<String> stderrStream() { return _logSplitter.split().expand((entry) { - if (entry.first != log.Level.ERROR && entry.first != log.Level.WARNING) { + if (entry.first != log.Level.error && entry.first != log.Level.warning) { return []; } return [entry.last]; @@ -592,9 +578,9 @@ /// A stream of log messages that are silent by default. Stream<String> silentStream() { return _logSplitter.split().expand((entry) { - if (entry.first == log.Level.MESSAGE) return []; - if (entry.first == log.Level.ERROR) return []; - if (entry.first == log.Level.WARNING) return []; + if (entry.first == log.Level.message) return []; + if (entry.first == log.Level.error) return []; + if (entry.first == log.Level.warning) return []; return [entry.last]; }); } @@ -617,15 +603,15 @@ /// [hosted] is a list of package names to version strings for dependencies on /// hosted packages. Future<void> createLockFile(String package, - {Iterable<String> dependenciesInSandBox, - Map<String, String> hosted}) async { + {Iterable<String>? dependenciesInSandBox, + Map<String, String>? hosted}) async { var cache = SystemCache(rootDir: _pathInSandbox(cachePath)); var lockFile = _createLockFile(cache.sources, sandbox: dependenciesInSandBox, hosted: hosted); await d.dir(package, [ - d.file('pubspec.lock', lockFile.serialize(null)), + d.file('pubspec.lock', lockFile.serialize(p.join(d.sandbox, package))), d.file( '.packages', lockFile.packagesFile( @@ -640,8 +626,8 @@ /// Like [createLockFile], but creates only a `.packages` file without a /// lockfile. Future<void> createPackagesFile(String package, - {Iterable<String> dependenciesInSandBox, - Map<String, String> hosted}) async { + {Iterable<String>? dependenciesInSandBox, + Map<String, String>? hosted}) async { var cache = SystemCache(rootDir: _pathInSandbox(cachePath)); var lockFile = _createLockFile(cache.sources, sandbox: dependenciesInSandBox, hosted: hosted); @@ -666,7 +652,7 @@ /// [hosted] is a list of package names to version strings for dependencies on /// hosted packages. LockFile _createLockFile(SourceRegistry sources, - {Iterable<String> sandbox, Map<String, String> hosted}) { + {Iterable<String>? sandbox, Map<String, String>? hosted}) { var dependencies = {}; if (sandbox != null) { @@ -677,7 +663,9 @@ var packages = dependencies.keys.map((name) { var dependencyPath = dependencies[name]; - return sources.path.idFor(name, Version(0, 0, 0), dependencyPath); + return sources.path.parseId( + name, Version(0, 0, 0), {'path': dependencyPath, 'relative': true}, + containingPath: p.join(d.sandbox, appPath)); }).toList(); if (hosted != null) { @@ -704,14 +692,14 @@ /// Describes a map representing a library package with the given [name], /// [version], and [dependencies]. -Map packageMap( +Map<String, Object> packageMap( String name, String version, [ - Map dependencies, - Map devDependencies, - Map environment, + Map? dependencies, + Map? devDependencies, + Map? environment, ]) { - var package = <String, dynamic>{ + var package = <String, Object>{ 'name': name, 'version': version, 'homepage': 'http://pub.dartlang.org', @@ -833,7 +821,7 @@ /// which may be a literal JSON object, or any other [Matcher]. void _validateOutputJson( List<String> failures, String pipe, expected, String actualText) { - Map actual; + late Map actual; try { actual = jsonDecode(actualText); } on FormatException { @@ -914,8 +902,9 @@ line = line .replaceAll(d.sandbox, r'$SANDBOX') .replaceAll(Platform.pathSeparator, '/'); - if (globalPackageServer != null) { - line = line.replaceAll(globalPackageServer.port.toString(), '\$PORT'); + var port = _globalServer?.port; + if (port != null) { + line = line.replaceAll(port.toString(), '\$PORT'); } return line; }); @@ -925,9 +914,9 @@ Future<void> runPubIntoBuffer( List<String> args, StringBuffer buffer, { - Map<String, String> environment, - String workingDirectory, - String stdin, + Map<String, String>? environment, + String? workingDirectory, + String? stdin, }) async { final process = await startPub( args: args, @@ -941,15 +930,49 @@ } final exitCode = await process.exitCode; + // TODO(jonasfj): Clean out temporary directory names from env vars... + // if (workingDirectory != null) { + // buffer.writeln('\$ cd $workingDirectory'); + // } + // if (environment != null && environment.isNotEmpty) { + // buffer.writeln(environment.entries + // .map((e) => '\$ export ${e.key}=${e.value}') + // .join('\n')); + // } buffer.writeln(_filter([ '\$ pub ${args.join(' ')}', ...await process.stdout.rest.toList(), ]).join('\n')); for (final line in _filter(await process.stderr.rest.toList())) { - buffer.writeln('[ERR] $line'); + buffer.writeln('[STDERR] $line'); } if (exitCode != 0) { - buffer.writeln('[Exit code] $exitCode'); + buffer.writeln('[EXIT CODE] $exitCode'); } buffer.write('\n'); } + +/// The current global [PackageServer]. +PackageServer get globalServer => _globalServer!; +PackageServer? _globalServer; + +/// Creates an HTTP server that replicates the structure of pub.dartlang.org and +/// makes it the current [globalServer]. +Future<PackageServer> servePackages() async { + final server = await startPackageServer(); + _globalServer = server; + + addTearDown(() { + _globalServer = null; + }); + return server; +} + +Future<PackageServer> startPackageServer() async { + final server = await PackageServer.start(); + + addTearDown(() async { + await server.close(); + }); + return server; +}
diff --git a/test/testdata/README.md b/test/testdata/README.md new file mode 100644 index 0000000..ad4a817 --- /dev/null +++ b/test/testdata/README.md
@@ -0,0 +1,25 @@ +# Test Data + +Data used in tests is called _test data_ and is located in this folder, or +sub-folders thereof. This is not for test files, this folder should not contain +test code, only data used in tests. + +## Golden Test + +The `test` wrapper `testWithGolden('<name>', (ctx) async {` will register a +test case, and create a file: + `test/testdata/goldens/path/to/myfile_test/<name>.txt` +, where `path/to/myfile_test.dart` is the name of the file containing the test +case, and `<name>` is the name of the test case. + +Any calls to `ctx.run` will run `pub` and compare the output to a section in the +golden file. If the file does not exist, it is created and the +test is marked as skipped. +Thus, it is safe to delete all files in `test/testdata/goldens` and recreate +them -- just carefully review the changes before committing. + +**Maintaining goldens**: + 1. Delete `test/testdata/goldens/`. + 2. Re-run tests to re-create files in `test/testdata/goldens/`. + 3. Compare changes, using `git diff test/testdata/goldens/`. +
diff --git a/test/dependency_services/goldens/dependency_report_adding_transitive.txt b/test/testdata/goldens/dependency_services/dependency_services_test/Adding transitive.txt similarity index 83% rename from test/dependency_services/goldens/dependency_report_adding_transitive.txt rename to test/testdata/goldens/dependency_services/dependency_services_test/Adding transitive.txt index 2a7fe2a..659163c 100644 --- a/test/dependency_services/goldens/dependency_report_adding_transitive.txt +++ b/test/testdata/goldens/dependency_services/dependency_services_test/Adding transitive.txt
@@ -1,4 +1,6 @@ -$ pub __experimental-dependency-services list +# GENERATED BY: test/dependency_services/dependency_services_test.dart + +$ bin/dependency_services.dart list { "dependencies": [ { @@ -10,7 +12,7 @@ ] } -$ pub __experimental-dependency-services report +$ bin/dependency_services.dart report { "dependencies": [ { @@ -52,10 +54,8 @@ ] } -$ pub __experimental-dependency-services apply -Resolving dependencies... -+ transitive 1.0.0 -Would change 1 dependency. +$ bin/dependency_services.dart apply +{"dependencies":[]} myapp/pubspec.yaml: {"name":"app","dependencies":{"foo":^2.2.3},"environment":{"sdk":">=0.1.2 <1.0.0"}} @@ -67,7 +67,7 @@ dependency: "direct main" description: name: foo - url: "http://localhost:34801" + url: "http://localhost:<port>" source: hosted version: 2.2.3 sdks:
diff --git a/test/dependency_services/goldens/dependency_report_removing_transitive.txt b/test/testdata/goldens/dependency_services/dependency_services_test/Removing transitive.txt similarity index 80% rename from test/dependency_services/goldens/dependency_report_removing_transitive.txt rename to test/testdata/goldens/dependency_services/dependency_services_test/Removing transitive.txt index c9bdee8..8f8cd13 100644 --- a/test/dependency_services/goldens/dependency_report_removing_transitive.txt +++ b/test/testdata/goldens/dependency_services/dependency_services_test/Removing transitive.txt
@@ -1,4 +1,6 @@ -$ pub __experimental-dependency-services list +# GENERATED BY: test/dependency_services/dependency_services_test.dart + +$ bin/dependency_services.dart list { "dependencies": [ { @@ -16,7 +18,7 @@ ] } -$ pub __experimental-dependency-services report +$ bin/dependency_services.dart report { "dependencies": [ { @@ -36,7 +38,7 @@ { "name": "transitive", "version": null, - "kind": null, + "kind": "transitive", "constraint": null } ], @@ -50,7 +52,7 @@ { "name": "transitive", "version": null, - "kind": null, + "kind": "transitive", "constraint": null } ] @@ -67,11 +69,8 @@ ] } -$ pub __experimental-dependency-services apply -Resolving dependencies... -These packages are no longer being depended on: -- transitive 1.0.0 -Would change 1 dependency. +$ bin/dependency_services.dart apply +{"dependencies":[]} myapp/pubspec.yaml: {"name":"app","dependencies":{"foo":^2.2.3},"environment":{"sdk":">=0.1.2 <1.0.0"}} @@ -83,14 +82,14 @@ dependency: "direct main" description: name: foo - url: "http://localhost:39343" + url: "http://localhost:<port>" source: hosted version: 2.2.3 transitive: dependency: transitive description: name: transitive - url: "http://localhost:39343" + url: "http://localhost:<port>" source: hosted version: "1.0.0" sdks:
diff --git a/test/deps/goldens/formatting.txt b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt similarity index 71% rename from test/deps/goldens/formatting.txt rename to test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt index ff5aec9..d8448df 100644 --- a/test/deps/goldens/formatting.txt +++ b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
@@ -1,3 +1,7 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree |-- bar | |-- bin | | '-- qux.dart @@ -10,18 +14,28 @@ '-- myapp |-- bin | '-- myapp.dart + |-- pubspec.lock '-- pubspec.yaml +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub deps --executables myapp foo: foo, baz bar:qux +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub deps --executables --dev myapp foo: foo, baz bar:qux +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub deps --json { "root": "myapp",
diff --git a/test/deps/goldens/dev_dependencies.txt b/test/testdata/goldens/deps/executables_test/dev dependencies.txt similarity index 62% rename from test/deps/goldens/dev_dependencies.txt rename to test/testdata/goldens/deps/executables_test/dev dependencies.txt index 3fb677c..2d72b44 100644 --- a/test/deps/goldens/dev_dependencies.txt +++ b/test/testdata/goldens/deps/executables_test/dev dependencies.txt
@@ -1,16 +1,30 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree |-- foo | |-- bin | | '-- bar.dart | '-- pubspec.yaml '-- myapp + |-- pubspec.lock '-- pubspec.yaml +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub deps --executables foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub deps --executables --dev foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub deps --json { "root": "myapp",
diff --git a/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt new file mode 100644 index 0000000..a12d363 --- /dev/null +++ b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
@@ -0,0 +1,50 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree +'-- myapp + |-- bin + | |-- bar.dart + | '-- foo.dart + |-- pubspec.lock + '-- pubspec.yaml + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub deps --executables +myapp: bar, foo + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 +$ pub deps --executables --dev +myapp: bar, foo + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + ":bar", + ":foo" + ] +} +
diff --git a/test/deps/goldens/only_immediate.txt b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt similarity index 62% copy from test/deps/goldens/only_immediate.txt copy to test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt index 5e42925..75a1b33 100644 --- a/test/deps/goldens/only_immediate.txt +++ b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
@@ -1,20 +1,30 @@ -|-- baz -| |-- bin -| | '-- qux.dart -| '-- pubspec.yaml +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree |-- foo | |-- bin | | '-- bar.dart | '-- pubspec.yaml '-- myapp + |-- pubspec.lock '-- pubspec.yaml +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub deps --executables foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub deps --executables --dev foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub deps --json { "root": "myapp", @@ -33,15 +43,6 @@ "version": "1.0.0", "kind": "direct", "source": "path", - "dependencies": [ - "baz" - ] - }, - { - "name": "baz", - "version": "1.0.0", - "kind": "transitive", - "source": "path", "dependencies": [] } ],
diff --git a/test/deps/goldens/only_immediate.txt b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt similarity index 68% rename from test/deps/goldens/only_immediate.txt rename to test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt index 5e42925..de70643 100644 --- a/test/deps/goldens/only_immediate.txt +++ b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
@@ -1,3 +1,7 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree |-- baz | |-- bin | | '-- qux.dart @@ -7,14 +11,24 @@ | | '-- bar.dart | '-- pubspec.yaml '-- myapp + |-- pubspec.lock '-- pubspec.yaml +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub deps --executables foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub deps --executables --dev foo:bar +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub deps --json { "root": "myapp",
diff --git a/test/deps/goldens/overrides.txt b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt similarity index 66% rename from test/deps/goldens/overrides.txt rename to test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt index ab76e79..910210e 100644 --- a/test/deps/goldens/overrides.txt +++ b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
@@ -1,3 +1,7 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree |-- foo-1.0 | |-- bin | | '-- bar.dart @@ -8,14 +12,24 @@ | | '-- baz.dart | '-- pubspec.yaml '-- myapp + |-- pubspec.lock '-- pubspec.yaml +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub deps --executables foo: bar, baz +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub deps --executables --dev foo: bar, baz +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub deps --json { "root": "myapp",
diff --git a/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt new file mode 100644 index 0000000..289f7c8 --- /dev/null +++ b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
@@ -0,0 +1,50 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree +'-- myapp + |-- bin + | |-- foo.dart + | '-- sub + | '-- bar.dart + |-- pubspec.lock + '-- pubspec.yaml + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub deps --executables +myapp:foo + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 +$ pub deps --executables --dev +myapp:foo + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [ + ":foo" + ] +} +
diff --git a/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt new file mode 100644 index 0000000..d4a2db3 --- /dev/null +++ b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
@@ -0,0 +1,45 @@ +# GENERATED BY: test/deps/executables_test.dart + +## Section 0 +$ tree +'-- myapp + |-- bin + | |-- bar.sh + | '-- foo.py + |-- pubspec.lock + '-- pubspec.yaml + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub deps --executables + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 +$ pub deps --executables --dev + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 +$ pub deps --json +{ + "root": "myapp", + "packages": [ + { + "name": "myapp", + "version": "0.0.0", + "kind": "root", + "source": "root", + "dependencies": [] + } + ], + "sdks": [ + { + "name": "Dart", + "version": "0.1.2+3" + } + ], + "executables": [] +} +
diff --git a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt new file mode 100644 index 0000000..237b3b5 --- /dev/null +++ b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
@@ -0,0 +1,126 @@ +# GENERATED BY: test/directory_option_test.dart + +## Section 0 +$ pub add --directory=myapp foo +Resolving dependencies in myapp... ++ foo 1.0.0 +Changed 1 dependency in myapp! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub -C myapp add bar +Resolving dependencies in myapp... ++ bar 1.2.3 +Changed 1 dependency in myapp! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 +$ pub -C myapp/example get --directory=myapp bar +Resolving dependencies in myapp... +Got dependencies in myapp! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 +$ pub remove bar -C myapp +Resolving dependencies in myapp... +These packages are no longer being depended on: +- bar 1.2.3 +Changed 1 dependency in myapp! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 +$ pub get bar -C myapp +Resolving dependencies in myapp... +Got dependencies in myapp! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 +$ pub get bar -C myapp/example +Resolving dependencies in myapp/example... ++ foo 1.0.0 ++ test_pkg 1.0.0 from path myapp +Changed 2 dependencies in myapp/example! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 +$ pub get bar -C myapp/example2 +Resolving dependencies in myapp/example2... +[STDERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp". +[STDERR] ╷ +[STDERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dartlang.org","description":"A package, I guess.","environment":{"sdk":">=1.8.0 <=2.0.0"}, dependencies: { foo: ^1.0.0}} +[STDERR] │ ^^^^^^^^^^ +[STDERR] ╵ +[EXIT CODE] 65 + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 +$ pub get bar -C myapp/broken_dir +[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp/broken_dir". +[EXIT CODE] 66 + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 +$ pub downgrade -C myapp +Resolving dependencies in myapp... + foo 1.0.0 +No dependencies changed in myapp. + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 +$ pub upgrade bar -C myapp +Resolving dependencies in myapp... + foo 1.0.0 +No dependencies changed in myapp. + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 +$ pub run -C myapp bin/app.dart +Building package executable... +Built test_pkg:app. +Hi + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 +$ pub publish -C myapp --dry-run +Publishing test_pkg 1.0.0 to http://localhost:$PORT: +|-- CHANGELOG.md +|-- LICENSE +|-- README.md +|-- bin +| '-- app.dart +|-- example +| '-- pubspec.yaml +|-- example2 +| '-- pubspec.yaml +|-- lib +| '-- test_pkg.dart +'-- pubspec.yaml +The server may enforce additional checks. +[STDERR] +[STDERR] Package has 0 warnings. + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 12 +$ pub uploader -C myapp add sigurdm@google.com +Good job! + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 13 +$ pub deps -C myapp +Dart SDK 1.12.0 +test_pkg 1.0.0 +'-- foo 1.0.0 +
diff --git a/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt b/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt new file mode 100644 index 0000000..fc69b03 --- /dev/null +++ b/test/testdata/goldens/embedding/embedding_test/logfile is written with --verbose and on unexpected exceptions.txt
@@ -0,0 +1,308 @@ +# GENERATED BY: test/embedding/embedding_test.dart + +$ tool/test-bin/pub_command_runner.dart pub --verbose get +MSG : Resolving dependencies... +MSG : + foo 1.0.0 +MSG : Downloading foo 1.0.0... +MSG : Changed 1 dependency! +MSG : Logs written to $SANDBOX/cache/log/pub_log.txt. +[E] FINE: Pub 0.1.2+3 +[E] SLVR: fact: myapp is 0.0.0 +[E] SLVR: derived: myapp +[E] SLVR: fact: myapp depends on foo any +[E] SLVR: selecting myapp +[E] SLVR: derived: foo any +[E] IO : Get versions from http://localhost:$PORT/api/packages/foo. +[E] IO : HTTP GET http://localhost:$PORT/api/packages/foo +[E] | Accept: application/vnd.pub.v2+json +[E] | X-Pub-OS: $OS +[E] | X-Pub-Command: get +[E] | X-Pub-Session-ID: $ID +[E] | X-Pub-Environment: test-environment +[E] | X-Pub-Reason: direct +[E] | user-agent: Dart pub 0.1.2+3 +[E] IO : HTTP response 200 OK for GET http://localhost:$PORT/api/packages/foo +[E] | took: $TIME +[E] | date: $TIME +[E] | content-length: 197 +[E] | x-frame-options: SAMEORIGIN +[E] | content-type: text/plain; charset=utf-8 +[E] | x-xss-protection: 1; mode=block +[E] | x-content-type-options: nosniff +[E] | server: dart:io with Shelf +[E] IO : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json. +[E] FINE: Contents: +[E] | {"name":"foo","uploaders":["nweiz@google.com"],"versions":[{"pubspec":{"name":"foo","version":"1.0.0"},"version":"1.0.0","archive_url":"http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz"}],"_fetchedAt": "$TIME"} +[E] SLVR: selecting foo 1.0.0 +[E] SLVR: Version solving took: $TIME +[E] | Tried 1 solutions. +[E] FINE: Resolving dependencies finished ($TIME) +[E] IO : Get package from http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz. +[E] IO : Created temp directory $DIR +[E] IO : HTTP GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz +[E] | X-Pub-OS: $OS +[E] | X-Pub-Command: get +[E] | X-Pub-Session-ID: $ID +[E] | X-Pub-Environment: test-environment +[E] | X-Pub-Reason: direct +[E] | user-agent: Dart pub 0.1.2+3 +[E] IO : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz +[E] | took: $TIME +[E] | transfer-encoding: chunked +[E] | date: $TIME +[E] | x-frame-options: SAMEORIGIN +[E] | content-type: text/plain; charset=utf-8 +[E] | x-xss-protection: 1; mode=block +[E] | x-content-type-options: nosniff +[E] | server: dart:io with Shelf +[E] IO : Creating $FILE from stream +[E] FINE: Created $FILE from stream +[E] IO : Created temp directory $DIR +[E] IO : Reading binary file $FILE. +[E] FINE: Extracting .tar.gz stream to $DIR +[E] IO : Creating $FILE from stream +[E] FINE: Created $FILE from stream +[E] IO : Creating $FILE from stream +[E] FINE: Created $FILE from stream +[E] FINE: Extracted .tar.gz to $DIR +[E] IO : Renaming directory $A to $B +[E] IO : Deleting directory $DIR +[E] IO : Writing $N characters to text file pubspec.lock. +[E] FINE: Contents: +[E] | # Generated by pub +[E] | # See https://dart.dev/tools/pub/glossary#lockfile +[E] | packages: +[E] | foo: +[E] | dependency: "direct main" +[E] | description: +[E] | name: foo +[E] | url: "http://localhost:$PORT" +[E] | source: hosted +[E] | version: "1.0.0" +[E] | sdks: +[E] | dart: ">=0.1.2 <1.0.0" +[E] IO : Writing $N characters to text file .dart_tool/package_config.json. +[E] FINE: Contents: +[E] | { +[E] | "configVersion": 2, +[E] | "packages": [ +[E] | { +[E] | "name": "foo", +[E] | "rootUri": "file://$SANDBOX/cache/hosted/localhost%2558$PORT/foo-1.0.0", +[E] | "packageUri": "lib/", +[E] | "languageVersion": "2.7" +[E] | }, +[E] | { +[E] | "name": "myapp", +[E] | "rootUri": "../", +[E] | "packageUri": "lib/", +[E] | "languageVersion": "0.1" +[E] | } +[E] | ], +[E] | "generated": "$TIME", +[E] | "generator": "pub", +[E] | "generatorVersion": "0.1.2+3" +[E] | } +[E] IO : Writing $N characters to text file $SANDBOX/cache/log/pub_log.txt. + +-------------------------------- END OF OUTPUT --------------------------------- + +Information about the latest pub run. + +If you believe something is not working right, you can go to +https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file. + +Before making this file public, make sure to remove any sensitive information! + +Pub version: 0.1.2+3 +Created: $TIME +FLUTTER_ROOT: <not set> +PUB_HOSTED_URL: http://localhost:$PORT +PUB_CACHE: "$SANDBOX/cache" +Command: dart pub --verbose get +Platform: $OS + +---- $SANDBOX/myapp/pubspec.yaml ---- +{"name":"myapp","environment":{"sdk":">=0.1.2 <1.0.0"},"dependencies":{"foo":"any"}} +---- End pubspec.yaml ---- +---- $SANDBOX/myapp/pubspec.lock ---- +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + foo: + dependency: "direct main" + description: + name: foo + url: "http://localhost:$PORT" + source: hosted + version: "1.0.0" +sdks: + dart: ">=0.1.2 <1.0.0" + +---- End pubspec.lock ---- +---- Log transcript ---- +FINE: Pub 0.1.2+3 +MSG : Resolving dependencies... +SLVR: fact: myapp is 0.0.0 +SLVR: derived: myapp +SLVR: fact: myapp depends on foo any +SLVR: selecting myapp +SLVR: derived: foo any +IO : Get versions from http://localhost:$PORT/api/packages/foo. +IO : HTTP GET http://localhost:$PORT/api/packages/foo + | Accept: application/vnd.pub.v2+json + | X-Pub-OS: $OS + | X-Pub-Command: get + | X-Pub-Session-ID: $ID + | X-Pub-Environment: test-environment + | X-Pub-Reason: direct + | user-agent: Dart pub 0.1.2+3 +IO : HTTP response 200 OK for GET http://localhost:$PORT/api/packages/foo + | took: $TIME + | date: $TIME + | content-length: 197 + | x-frame-options: SAMEORIGIN + | content-type: text/plain; charset=utf-8 + | x-xss-protection: 1; mode=block + | x-content-type-options: nosniff + | server: dart:io with Shelf +IO : Writing $N characters to text file $SANDBOX/cache/hosted/localhost%58$PORT/.cache/foo-versions.json. +FINE: Contents: + | {"name":"foo","uploaders":["nweiz@google.com"],"versions":[{"pubspec":{"name":"foo","version":"1.0.0"},"version":"1.0.0","archive_url":"http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz"}],"_fetchedAt": "$TIME"} +SLVR: selecting foo 1.0.0 +SLVR: Version solving took: $TIME + | Tried 1 solutions. +FINE: Resolving dependencies finished ($TIME) +MSG : + foo 1.0.0 +IO : Get package from http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz. +MSG : Downloading foo 1.0.0... +IO : Created temp directory $DIR +IO : HTTP GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz + | X-Pub-OS: $OS + | X-Pub-Command: get + | X-Pub-Session-ID: $ID + | X-Pub-Environment: test-environment + | X-Pub-Reason: direct + | user-agent: Dart pub 0.1.2+3 +IO : HTTP response 200 OK for GET http://localhost:$PORT/packages/foo/versions/1.0.0.tar.gz + | took: $TIME + | transfer-encoding: chunked + | date: $TIME + | x-frame-options: SAMEORIGIN + | content-type: text/plain; charset=utf-8 + | x-xss-protection: 1; mode=block + | x-content-type-options: nosniff + | server: dart:io with Shelf +IO : Creating $FILE from stream +FINE: Created $FILE from stream +IO : Created temp directory $DIR +IO : Reading binary file $FILE. +FINE: Extracting .tar.gz stream to $DIR +IO : Creating $FILE from stream +FINE: Created $FILE from stream +IO : Creating $FILE from stream +FINE: Created $FILE from stream +FINE: Extracted .tar.gz to $DIR +IO : Renaming directory $A to $B +IO : Deleting directory $DIR +IO : Writing $N characters to text file pubspec.lock. +FINE: Contents: + | # Generated by pub + | # See https://dart.dev/tools/pub/glossary#lockfile + | packages: + | foo: + | dependency: "direct main" + | description: + | name: foo + | url: "http://localhost:$PORT" + | source: hosted + | version: "1.0.0" + | sdks: + | dart: ">=0.1.2 <1.0.0" +MSG : Changed 1 dependency! +IO : Writing $N characters to text file .dart_tool/package_config.json. +FINE: Contents: + | { + | "configVersion": 2, + | "packages": [ + | { + | "name": "foo", + | "rootUri": "file://$SANDBOX/cache/hosted/localhost%2558$PORT/foo-1.0.0", + | "packageUri": "lib/", + | "languageVersion": "2.7" + | }, + | { + | "name": "myapp", + | "rootUri": "../", + | "packageUri": "lib/", + | "languageVersion": "0.1" + | } + | ], + | "generated": "$TIME", + | "generator": "pub", + | "generatorVersion": "0.1.2+3" + | } +---- End log transcript ---- +-------------------------------- END OF OUTPUT --------------------------------- + +$ tool/test-bin/pub_command_runner.dart pub fail +[E] Bad state: Pub has crashed +[E] tool/test-bin/pub_command_runner.dart $LINE:$COL ThrowingCommand.runProtected +[E] package:pub/src/command.dart $LINE:$COL PubCommand.run.<fn> +[E] package:pub/src/command.dart $LINE:$COL PubCommand.run.<fn> +[E] dart:async new Future.sync +[E] package:pub/src/utils.dart $LINE:$COL captureErrors.wrappedCallback +[E] dart:async runZonedGuarded +[E] package:pub/src/utils.dart $LINE:$COL captureErrors +[E] package:pub/src/command.dart $LINE:$COL PubCommand.run +[E] package:args/command_runner.dart $LINE:$COL CommandRunner.runCommand +[E] tool/test-bin/pub_command_runner.dart $LINE:$COL Runner.runCommand +[E] tool/test-bin/pub_command_runner.dart $LINE:$COL Runner.run +[E] tool/test-bin/pub_command_runner.dart $LINE:$COL main +[E] This is an unexpected error. The full log and other details are collected in: +[E] +[E] $SANDBOX/cache/log/pub_log.txt +[E] +[E] Consider creating an issue on https://github.com/dart-lang/pub/issues/new +[E] and attaching the relevant parts of that log file. + +-------------------------------- END OF OUTPUT --------------------------------- + +Information about the latest pub run. + +If you believe something is not working right, you can go to +https://github.com/dart-lang/pub/issues/new to post a new issue and attach this file. + +Before making this file public, make sure to remove any sensitive information! + +Pub version: 0.1.2+3 +Created: $TIME +FLUTTER_ROOT: <not set> +PUB_HOSTED_URL: http://localhost:$PORT +PUB_CACHE: "$SANDBOX/cache" +Command: dart pub fail +Platform: $OS + +---- Log transcript ---- +FINE: Pub 0.1.2+3 +ERR : Bad state: Pub has crashed +FINE: Exception type: StateError +ERR : tool/test-bin/pub_command_runner.dart $LINE:$COL ThrowingCommand.runProtected + | package:pub/src/command.dart $LINE:$COL PubCommand.run.<fn> + | package:pub/src/command.dart $LINE:$COL PubCommand.run.<fn> + | dart:async new Future.sync + | package:pub/src/utils.dart $LINE:$COL captureErrors.wrappedCallback + | dart:async runZonedGuarded + | package:pub/src/utils.dart $LINE:$COL captureErrors + | package:pub/src/command.dart $LINE:$COL PubCommand.run + | package:args/command_runner.dart $LINE:$COL CommandRunner.runCommand + | tool/test-bin/pub_command_runner.dart $LINE:$COL Runner.runCommand + | tool/test-bin/pub_command_runner.dart $LINE:$COL Runner.run + | tool/test-bin/pub_command_runner.dart $LINE:$COL main +ERR : This is an unexpected error. The full log and other details are collected in: + | + | $SANDBOX/cache/log/pub_log.txt + | + | Consider creating an issue on https://github.com/dart-lang/pub/issues/new + | and attaching the relevant parts of that log file. +---- End log transcript ----
diff --git a/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt b/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt new file mode 100644 index 0000000..214712a --- /dev/null +++ b/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/embedding/embedding_test.dart + +$ tool/test-bin/pub_command_runner.dart pub get +Resolving dependencies... +Got dependencies! + +-------------------------------- END OF OUTPUT --------------------------------- + +$ tool/test-bin/pub_command_runner.dart pub run bin/main.dart +Hi +
diff --git a/test/testdata/goldens/help_test/pub add --help.txt b/test/testdata/goldens/help_test/pub add --help.txt new file mode 100644 index 0000000..3d1f429 --- /dev/null +++ b/test/testdata/goldens/help_test/pub add --help.txt
@@ -0,0 +1,27 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub add --help +Add dependencies to pubspec.yaml. + +Usage: pub add <package>[:<constraint>] [<package2>[:<constraint2>]...] [options] +-h, --help Print this usage information. +-d, --dev Adds to the development dependencies instead. + --git-url Git URL of the package + --git-ref Git branch or commit to be retrieved + --git-path Path of git package in repository + --hosted-url URL of package host server + --path Add package from local path + --sdk=<[flutter]> add package from SDK source + [flutter] + --[no-]offline Use cached packages instead of accessing the + network. +-n, --dry-run Report what dependencies would change but don't + change any. + --[no-]precompile Build executables in immediate dependencies. +-C, --directory=<dir> Run this in the directory <dir>. + --legacy-packages-file Generate the legacy ".packages" file + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-add for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub cache --help.txt b/test/testdata/goldens/help_test/pub cache --help.txt new file mode 100644 index 0000000..fdb0b2c --- /dev/null +++ b/test/testdata/goldens/help_test/pub cache --help.txt
@@ -0,0 +1,17 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub cache --help +Work with the system cache. + +Usage: pub cache [arguments...] +-h, --help Print this usage information. + +Available subcommands: + add Install a package. + clean Clears the global PUB_CACHE. + repair Reinstall cached packages. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub cache add --help.txt b/test/testdata/goldens/help_test/pub cache add --help.txt new file mode 100644 index 0000000..05068f0 --- /dev/null +++ b/test/testdata/goldens/help_test/pub cache add --help.txt
@@ -0,0 +1,14 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub cache add --help +Install a package. + +Usage: pub cache add <package> [--version <constraint>] [--all] +-h, --help Print this usage information. + --all Install all matching versions. +-v, --version Version constraint. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub cache clean --help.txt b/test/testdata/goldens/help_test/pub cache clean --help.txt new file mode 100644 index 0000000..71dd1d6 --- /dev/null +++ b/test/testdata/goldens/help_test/pub cache clean --help.txt
@@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub cache clean --help +Clears the global PUB_CACHE. + +Usage: pub cache clean <subcommand> [arguments...] +-h, --help Print this usage information. +-f, --force Don't ask for confirmation. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub cache repair --help.txt b/test/testdata/goldens/help_test/pub cache repair --help.txt new file mode 100644 index 0000000..ac09115 --- /dev/null +++ b/test/testdata/goldens/help_test/pub cache repair --help.txt
@@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub cache repair --help +Reinstall cached packages. + +Usage: pub cache repair <subcommand> [arguments...] +-h, --help Print this usage information. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub deps --help.txt b/test/testdata/goldens/help_test/pub deps --help.txt new file mode 100644 index 0000000..475353f --- /dev/null +++ b/test/testdata/goldens/help_test/pub deps --help.txt
@@ -0,0 +1,19 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub deps --help +Print package dependencies. + +Usage: pub deps [arguments...] +-h, --help Print this usage information. +-s, --style How output should be displayed. + [compact, tree (default), list] + --[no-]dev Whether to include dev dependencies. + (defaults to on) + --executables List all available executables. + --json Output dependency information in a json format. +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-deps for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub downgrade --help.txt b/test/testdata/goldens/help_test/pub downgrade --help.txt new file mode 100644 index 0000000..ddf71e7 --- /dev/null +++ b/test/testdata/goldens/help_test/pub downgrade --help.txt
@@ -0,0 +1,20 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub downgrade --help +Downgrade the current package's dependencies to oldest versions. + + + +Usage: pub downgrade [dependencies...] +-h, --help Print this usage information. + --[no-]offline Use cached packages instead of accessing the + network. +-n, --dry-run Report what dependencies would change but don't + change any. +-C, --directory=<dir> Run this in the directory<dir>. + --legacy-packages-file Generate the legacy ".packages" file + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-downgrade for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub get --help.txt b/test/testdata/goldens/help_test/pub get --help.txt new file mode 100644 index 0000000..104f69c --- /dev/null +++ b/test/testdata/goldens/help_test/pub get --help.txt
@@ -0,0 +1,19 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub get --help +Get the current package's dependencies. + +Usage: pub get <subcommand> [arguments...] +-h, --help Print this usage information. + --[no-]offline Use cached packages instead of accessing the + network. +-n, --dry-run Report what dependencies would change but don't + change any. + --[no-]precompile Build executables in immediate dependencies. + --legacy-packages-file Generate the legacy ".packages" file +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub global --help.txt b/test/testdata/goldens/help_test/pub global --help.txt new file mode 100644 index 0000000..6aa723c --- /dev/null +++ b/test/testdata/goldens/help_test/pub global --help.txt
@@ -0,0 +1,18 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub global --help +Work with global packages. + +Usage: pub global [arguments...] +-h, --help Print this usage information. + +Available subcommands: + activate Make a package's executables globally available. + deactivate Remove a previously activated package. + list List globally activated packages. + run Run an executable from a globally activated package. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub global activate --help.txt b/test/testdata/goldens/help_test/pub global activate --help.txt new file mode 100644 index 0000000..5341266 --- /dev/null +++ b/test/testdata/goldens/help_test/pub global activate --help.txt
@@ -0,0 +1,19 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub global activate --help +Make a package's executables globally available. + +Usage: pub global activate <package> [version-constraint] +-h, --help Print this usage information. +-s, --source The source used to find the package. + [git, hosted (default), path] + --no-executables Do not put executables on PATH. +-x, --executable Executable(s) to place on PATH. + --overwrite Overwrite executables from other packages with the same + name. +-u, --hosted-url A custom pub server URL for the package. Only applies + when using the `hosted` source. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub global deactivate --help.txt b/test/testdata/goldens/help_test/pub global deactivate --help.txt new file mode 100644 index 0000000..8b8178b --- /dev/null +++ b/test/testdata/goldens/help_test/pub global deactivate --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub global deactivate --help +Remove a previously activated package. + +Usage: pub global deactivate <package> +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub global list --help.txt b/test/testdata/goldens/help_test/pub global list --help.txt new file mode 100644 index 0000000..12244be --- /dev/null +++ b/test/testdata/goldens/help_test/pub global list --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub global list --help +List globally activated packages. + +Usage: pub global list <subcommand> [arguments...] +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub global run --help.txt b/test/testdata/goldens/help_test/pub global run --help.txt new file mode 100644 index 0000000..f829064 --- /dev/null +++ b/test/testdata/goldens/help_test/pub global run --help.txt
@@ -0,0 +1,18 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub global run --help +Run an executable from a globally activated package. + +Usage: pub global run <package>:<executable> [args...] +-h, --help Print this usage information. + --[no-]enable-asserts Enable assert statements. + --enable-experiment=<experiment> Runs the executable in a VM with the + given experiments enabled. (Will disable + snapshotting, resulting in slower + startup). + --[no-]sound-null-safety Override the default null safety + execution mode. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub login --help.txt b/test/testdata/goldens/help_test/pub login --help.txt new file mode 100644 index 0000000..ce7233b --- /dev/null +++ b/test/testdata/goldens/help_test/pub login --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub login --help +Log into pub.dev. + +Usage: pub login +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub logout --help.txt b/test/testdata/goldens/help_test/pub logout --help.txt new file mode 100644 index 0000000..3937ef7 --- /dev/null +++ b/test/testdata/goldens/help_test/pub logout --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub logout --help +Log out of pub.dev. + +Usage: pub logout <subcommand> [arguments...] +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/outdated/goldens/helptext.txt b/test/testdata/goldens/help_test/pub outdated --help.txt similarity index 96% rename from test/outdated/goldens/helptext.txt rename to test/testdata/goldens/help_test/pub outdated --help.txt index 20a4ecc..9a7b1bc 100644 --- a/test/outdated/goldens/helptext.txt +++ b/test/testdata/goldens/help_test/pub outdated --help.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 $ pub outdated --help Analyze your dependencies to find which ones can be upgraded.
diff --git a/test/testdata/goldens/help_test/pub publish --help.txt b/test/testdata/goldens/help_test/pub publish --help.txt new file mode 100644 index 0000000..2977db0 --- /dev/null +++ b/test/testdata/goldens/help_test/pub publish --help.txt
@@ -0,0 +1,15 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub publish --help +Publish the current package to pub.dartlang.org. + +Usage: pub publish [options] +-h, --help Print this usage information. +-n, --dry-run Validate but do not publish the package. +-f, --force Publish without confirmation if there are no errors. +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub remove --help.txt b/test/testdata/goldens/help_test/pub remove --help.txt new file mode 100644 index 0000000..b82f9b6 --- /dev/null +++ b/test/testdata/goldens/help_test/pub remove --help.txt
@@ -0,0 +1,19 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub remove --help +Removes a dependency from the current package. + +Usage: pub remove <package> +-h, --help Print this usage information. + --[no-]offline Use cached packages instead of accessing the + network. +-n, --dry-run Report what dependencies would change but don't + change any. + --[no-]precompile Precompile executables in immediate dependencies. +-C, --directory=<dir> Run this in the directory<dir>. + --legacy-packages-file Generate the legacy ".packages" file + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-remove for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub run --help.txt b/test/testdata/goldens/help_test/pub run --help.txt new file mode 100644 index 0000000..f2844f3 --- /dev/null +++ b/test/testdata/goldens/help_test/pub run --help.txt
@@ -0,0 +1,20 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub run --help +Run an executable from a package. + +Usage: pub run <executable> [arguments...] +-h, --help Print this usage information. + --[no-]enable-asserts Enable assert statements. + --enable-experiment=<experiment> Runs the executable in a VM with the + given experiments enabled. + (Will disable snapshotting, resulting in + slower startup). + --[no-]sound-null-safety Override the default null safety + execution mode. +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub token --help.txt b/test/testdata/goldens/help_test/pub token --help.txt new file mode 100644 index 0000000..fa164c5 --- /dev/null +++ b/test/testdata/goldens/help_test/pub token --help.txt
@@ -0,0 +1,16 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub token --help +Manage authentication tokens for hosted pub repositories. + +Usage: pub token [arguments...] +-h, --help Print this usage information. + +Available subcommands: + add Add authentication tokens for a package repository. + list List servers for which a token exists. + remove Remove secret token for package repository. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub token add --help.txt b/test/testdata/goldens/help_test/pub token add --help.txt new file mode 100644 index 0000000..7068a5c --- /dev/null +++ b/test/testdata/goldens/help_test/pub token add --help.txt
@@ -0,0 +1,13 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub token add --help +Add authentication tokens for a package repository. + +Usage: pub token add +-h, --help Print this usage information. + --env-var Read the secret token from this environment variable when + making requests. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub token list --help.txt b/test/testdata/goldens/help_test/pub token list --help.txt new file mode 100644 index 0000000..5c333b5 --- /dev/null +++ b/test/testdata/goldens/help_test/pub token list --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub token list --help +List servers for which a token exists. + +Usage: pub token list +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub token remove --help.txt b/test/testdata/goldens/help_test/pub token remove --help.txt new file mode 100644 index 0000000..1f79f81 --- /dev/null +++ b/test/testdata/goldens/help_test/pub token remove --help.txt
@@ -0,0 +1,12 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub token remove --help +Remove secret token for package repository. + +Usage: pub token remove +-h, --help Print this usage information. + --all Remove all secret tokens. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/help_test/pub upgrade --help.txt b/test/testdata/goldens/help_test/pub upgrade --help.txt new file mode 100644 index 0000000..c787951 --- /dev/null +++ b/test/testdata/goldens/help_test/pub upgrade --help.txt
@@ -0,0 +1,23 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub upgrade --help +Upgrade the current package's dependencies to latest versions. + +Usage: pub upgrade [dependencies...] +-h, --help Print this usage information. + --[no-]offline Use cached packages instead of accessing the + network. +-n, --dry-run Report what dependencies would change but don't + change any. + --[no-]precompile Precompile executables in immediate dependencies. + --null-safety Upgrade constraints in pubspec.yaml to null-safety + versions + --legacy-packages-file Generate the legacy ".packages" file + --major-versions Upgrades packages to their latest resolvable + versions, and updates pubspec.yaml. +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-upgrade for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub uploader --help.txt b/test/testdata/goldens/help_test/pub uploader --help.txt new file mode 100644 index 0000000..10c9d9d --- /dev/null +++ b/test/testdata/goldens/help_test/pub uploader --help.txt
@@ -0,0 +1,15 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub uploader --help +Manage uploaders for a package on pub.dartlang.org. + +Usage: pub uploader [options] {add/remove} <email> +-h, --help Print this usage information. + --package The package whose uploaders will be modified. + (defaults to the current package) +-C, --directory=<dir> Run this in the directory<dir>. + +Run "pub help" to see global options. +See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation. +
diff --git a/test/testdata/goldens/help_test/pub version --help.txt b/test/testdata/goldens/help_test/pub version --help.txt new file mode 100644 index 0000000..82e9f9f --- /dev/null +++ b/test/testdata/goldens/help_test/pub version --help.txt
@@ -0,0 +1,11 @@ +# GENERATED BY: test/help_test.dart + +## Section 0 +$ pub version --help +Print pub version. + +Usage: pub version +-h, --help Print this usage information. + +Run "pub help" to see global options. +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt new file mode 100644 index 0000000..8dcaaf5 --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401-with-message.txt
@@ -0,0 +1,13 @@ +# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart + +## Section 0 +$ pub get +Resolving dependencies... +[STDERR] Because myapp depends on foo any which doesn't exist (authentication failed), version solving failed. +[STDERR] +[STDERR] http://localhost:$PORT package repository requested authentication! +[STDERR] You can provide credentials using: +[STDERR] pub token add http://localhost:$PORT +[STDERR] <message> +[EXIT CODE] 69 +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt new file mode 100644 index 0000000..68d5bd0 --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/401.txt
@@ -0,0 +1,12 @@ +# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart + +## Section 0 +$ pub get +Resolving dependencies... +[STDERR] Because myapp depends on foo any which doesn't exist (authentication failed), version solving failed. +[STDERR] +[STDERR] http://localhost:$PORT package repository requested authentication! +[STDERR] You can provide credentials using: +[STDERR] pub token add http://localhost:$PORT +[EXIT CODE] 69 +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt new file mode 100644 index 0000000..882660c --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403-with-message.txt
@@ -0,0 +1,13 @@ +# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart + +## Section 0 +$ pub get +Resolving dependencies... +[STDERR] Because myapp depends on foo any which doesn't exist (authorization failed), version solving failed. +[STDERR] +[STDERR] Insufficient permissions to the resource at the http://localhost:$PORT package repository. +[STDERR] You can modify credentials using: +[STDERR] pub token add http://localhost:$PORT +[STDERR] <message> +[EXIT CODE] 69 +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt new file mode 100644 index 0000000..f8a5af9 --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/403.txt
@@ -0,0 +1,12 @@ +# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart + +## Section 0 +$ pub get +Resolving dependencies... +[STDERR] Because myapp depends on foo any which doesn't exist (authorization failed), version solving failed. +[STDERR] +[STDERR] Insufficient permissions to the resource at the http://localhost:$PORT package repository. +[STDERR] You can modify credentials using: +[STDERR] pub token add http://localhost:$PORT +[EXIT CODE] 69 +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt new file mode 100644 index 0000000..8e446c2 --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_on_bad_version_listing_response_test/bad_json.txt
@@ -0,0 +1,10 @@ +# GENERATED BY: test/hosted/fail_gracefully_on_bad_version_listing_response_test.dart + +## Section 0 +$ pub get +Resolving dependencies... +[STDERR] Because myapp depends on foo any which doesn't exist (Got badly formatted response trying to find package foo at http://localhost:$PORT), version solving failed. +[STDERR] +[STDERR] Check that "http://localhost:$PORT" is a valid package repository. +[EXIT CODE] 65 +
diff --git a/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt b/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt new file mode 100644 index 0000000..a45b0f0 --- /dev/null +++ b/test/testdata/goldens/hosted/fail_gracefully_with_hint_test/supports two hints.txt
@@ -0,0 +1,13 @@ +# GENERATED BY: test/hosted/fail_gracefully_with_hint_test.dart + +## Section 0 +$ pub get --offline +Resolving dependencies... +[STDERR] Because foo <1.2.4 requires the Flutter SDK and foo >=1.2.4 depends on bar any, every version of foo requires bar any. +[STDERR] So, because bar doesn't exist (could not find package bar in cache) and myapp depends on foo any, version solving failed. +[STDERR] +[STDERR] Flutter users should run `flutter pub get` instead of `dart pub get`. +[STDERR] +[STDERR] Try again without --offline! +[EXIT CODE] 69 +
diff --git a/test/outdated/goldens/handles_sdk_dependencies.txt b/test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt similarity index 84% rename from test/outdated/goldens/handles_sdk_dependencies.txt rename to test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt index aba2f87..c9bc73f 100644 --- a/test/outdated/goldens/handles_sdk_dependencies.txt +++ b/test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -19,6 +22,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -33,6 +39,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -47,6 +56,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -63,6 +75,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -77,6 +92,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -89,6 +107,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -103,6 +124,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -119,6 +143,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -135,6 +162,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -151,6 +181,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -195,6 +228,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/circular_dependencies.txt b/test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt similarity index 80% rename from test/outdated/goldens/circular_dependencies.txt rename to test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt index 27b6202..b9ab0a5 100644 --- a/test/outdated/goldens/circular_dependencies.txt +++ b/test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -19,6 +22,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -31,6 +37,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -43,6 +52,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -55,6 +67,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -67,6 +82,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -79,6 +97,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -91,6 +112,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -104,6 +128,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -117,6 +144,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -130,6 +160,9 @@ 1 upgradable dependency is locked (in pubspec.lock) to an older version. To update it, use `dart pub upgrade`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -155,6 +188,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt b/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt new file mode 100644 index 0000000..6ab6163 --- /dev/null +++ b/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt
@@ -0,0 +1,64 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 +$ pub outdated random_argument +[STDERR] Command "outdated" does not take any arguments. +[STDERR] +[STDERR] Usage: pub outdated [options] +[STDERR] -h, --help Print this usage information. +[STDERR] --[no-]color Whether to color the output. +[STDERR] Defaults to color when connected to a +[STDERR] terminal, and no-color otherwise. +[STDERR] --[no-]dependency-overrides Show resolutions with `dependency_overrides`. +[STDERR] (defaults to on) +[STDERR] --[no-]dev-dependencies Take dev dependencies into account. +[STDERR] (defaults to on) +[STDERR] --json Output the results using a json format. +[STDERR] --mode=<PROPERTY> Highlight versions with PROPERTY. +[STDERR] Only packages currently missing that PROPERTY +[STDERR] will be included unless --show-all. +[STDERR] [outdated (default), null-safety] +[STDERR] --[no-]prereleases Include prereleases in latest version. +[STDERR] (defaults to on in --mode=null-safety). +[STDERR] --[no-]show-all Include dependencies that are already +[STDERR] fullfilling --mode. +[STDERR] --[no-]transitive Show transitive dependencies. +[STDERR] (defaults to off in --mode=null-safety). +[STDERR] -C, --directory=<dir> Run this in the directory<dir>. +[STDERR] +[STDERR] Run "pub help" to see global options. +[STDERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation. +[EXIT CODE] 64 + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub outdated --bad_flag +[STDERR] Could not find an option named "bad_flag". +[STDERR] +[STDERR] Usage: pub outdated [options] +[STDERR] -h, --help Print this usage information. +[STDERR] --[no-]color Whether to color the output. +[STDERR] Defaults to color when connected to a +[STDERR] terminal, and no-color otherwise. +[STDERR] --[no-]dependency-overrides Show resolutions with `dependency_overrides`. +[STDERR] (defaults to on) +[STDERR] --[no-]dev-dependencies Take dev dependencies into account. +[STDERR] (defaults to on) +[STDERR] --json Output the results using a json format. +[STDERR] --mode=<PROPERTY> Highlight versions with PROPERTY. +[STDERR] Only packages currently missing that PROPERTY +[STDERR] will be included unless --show-all. +[STDERR] [outdated (default), null-safety] +[STDERR] --[no-]prereleases Include prereleases in latest version. +[STDERR] (defaults to on in --mode=null-safety). +[STDERR] --[no-]show-all Include dependencies that are already +[STDERR] fullfilling --mode. +[STDERR] --[no-]transitive Show transitive dependencies. +[STDERR] (defaults to off in --mode=null-safety). +[STDERR] -C, --directory=<dir> Run this in the directory<dir>. +[STDERR] +[STDERR] Run "pub help" to see global options. +[STDERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation. +[EXIT CODE] 64 +
diff --git a/test/outdated/goldens/prereleases.txt b/test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt similarity index 87% rename from test/outdated/goldens/prereleases.txt rename to test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt index 8b91475..12c2ee3 100644 --- a/test/outdated/goldens/prereleases.txt +++ b/test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -34,6 +37,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -47,6 +53,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -60,6 +69,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -74,6 +86,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -88,6 +103,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -101,6 +119,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -114,6 +135,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -129,6 +153,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -144,6 +171,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -159,6 +189,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -222,6 +255,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/mutually_incompatible.txt b/test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt similarity index 84% rename from test/outdated/goldens/mutually_incompatible.txt rename to test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt index ae40331..18baa88 100644 --- a/test/outdated/goldens/mutually_incompatible.txt +++ b/test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -34,6 +37,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -46,6 +52,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -58,6 +67,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -70,6 +82,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -82,6 +97,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -94,6 +112,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -106,6 +127,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -119,6 +143,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -132,6 +159,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -145,6 +175,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -189,6 +222,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/newer_versions.txt b/test/testdata/goldens/outdated/outdated_test/newer versions available.txt similarity index 91% rename from test/outdated/goldens/newer_versions.txt rename to test/testdata/goldens/outdated/outdated_test/newer versions available.txt index 6e74a3e..d6c0ff9 100644 --- a/test/outdated/goldens/newer_versions.txt +++ b/test/testdata/goldens/outdated/outdated_test/newer versions available.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -84,6 +87,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -110,6 +116,9 @@ 3 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -128,6 +137,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -156,6 +168,9 @@ 3 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -182,6 +197,9 @@ 3 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -200,6 +218,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -226,6 +247,9 @@ 3 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -247,6 +271,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -276,6 +303,9 @@ 3 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -297,6 +327,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -440,6 +473,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/no_dependencies.txt b/test/testdata/goldens/outdated/outdated_test/no dependencies.txt similarity index 63% rename from test/outdated/goldens/no_dependencies.txt rename to test/testdata/goldens/outdated/outdated_test/no dependencies.txt index 672c124..d256d7f 100644 --- a/test/outdated/goldens/no_dependencies.txt +++ b/test/testdata/goldens/outdated/outdated_test/no dependencies.txt
@@ -1,44 +1,68 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -46,6 +70,9 @@ All your dependencies declare support for null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -53,6 +80,9 @@ All your dependencies declare support for null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -60,11 +90,17 @@ All your dependencies declare support for null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": []
diff --git a/test/outdated/goldens/no_lockfile.txt b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt similarity index 86% rename from test/outdated/goldens/no_lockfile.txt rename to test/testdata/goldens/outdated/outdated_test/no lockfile.txt index bca5ab7..7f670db 100644 --- a/test/outdated/goldens/no_lockfile.txt +++ b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -30,6 +33,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -46,6 +52,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -62,6 +71,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -78,6 +90,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -94,6 +109,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -110,6 +128,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -126,6 +147,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -143,6 +167,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -160,6 +187,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -177,6 +207,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -215,6 +248,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/testdata/goldens/outdated/outdated_test/no pubspec.txt b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt new file mode 100644 index 0000000..ba8858a --- /dev/null +++ b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
@@ -0,0 +1,7 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 +$ pub outdated +[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp". +[EXIT CODE] 66 +
diff --git a/test/outdated/goldens/null_safety.txt b/test/testdata/goldens/outdated/outdated_test/null safety compliance.txt similarity index 90% rename from test/outdated/goldens/null_safety.txt rename to test/testdata/goldens/outdated/outdated_test/null safety compliance.txt index 9a9ce9c..d345f55 100644 --- a/test/outdated/goldens/null_safety.txt +++ b/test/testdata/goldens/outdated/outdated_test/null safety compliance.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -94,6 +97,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -111,6 +117,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -128,6 +137,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -145,6 +157,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -162,6 +177,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -179,6 +197,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -196,6 +217,9 @@ 6 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -210,6 +234,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -224,6 +251,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -238,6 +268,9 @@ 2 dependencies are constrained to versions that are older than a resolvable version. To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -282,6 +315,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/null_safety_already_migrated.txt b/test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt similarity index 74% rename from test/outdated/goldens/null_safety_already_migrated.txt rename to test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt index b7ad48e..3d227ec 100644 --- a/test/outdated/goldens/null_safety_already_migrated.txt +++ b/test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt
@@ -1,20 +1,32 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -32,24 +44,36 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -62,6 +86,9 @@ dev_dependencies: all support null safety. All dependencies opt in to null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -77,6 +104,9 @@ devTransitive ✗1.0.0 ✗1.0.0 ✗1.0.0 ✗1.0.0 All dependencies opt in to null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -89,6 +119,9 @@ dev_dependencies: all support null safety. All dependencies opt in to null-safety. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -114,6 +147,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": []
diff --git a/test/outdated/goldens/null_safety_no_resolution.txt b/test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt similarity index 78% rename from test/outdated/goldens/null_safety_no_resolution.txt rename to test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt index 89fb0e2..1ab20ad 100644 --- a/test/outdated/goldens/null_safety_no_resolution.txt +++ b/test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt
@@ -1,20 +1,32 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -27,6 +39,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -39,18 +54,27 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. Found no outdated packages +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -63,6 +87,9 @@ foo ✗1.0.0 ✗1.0.0 - ✓2.0.0-nullsafety.0 No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -75,6 +102,9 @@ foo ✗1.0.0 ✗1.0.0 - ✓2.0.0-nullsafety.0 No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -87,6 +117,9 @@ foo ✗1.0.0 ✗1.0.0 - ✗1.0.0 No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -125,6 +158,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": []
diff --git a/test/outdated/goldens/dependency_overrides_no_solution.txt b/test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt similarity index 86% rename from test/outdated/goldens/dependency_overrides_no_solution.txt rename to test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt index 9efeb58..909ee0a 100644 --- a/test/outdated/goldens/dependency_overrides_no_solution.txt +++ b/test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -40,6 +43,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -52,6 +58,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -64,6 +73,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -76,6 +88,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -88,6 +103,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -100,6 +118,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -111,6 +132,9 @@ foo *1.0.0 (overridden) - - 2.0.0 No resolution was found. Try running `dart pub upgrade --dry-run` to explore why. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -124,6 +148,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -137,6 +164,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -150,6 +180,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -200,6 +233,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/outdated/goldens/dependency_overrides.txt b/test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt similarity index 89% rename from test/outdated/goldens/dependency_overrides.txt rename to test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt index eb0c881..49abe1b 100644 --- a/test/outdated/goldens/dependency_overrides.txt +++ b/test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/outdated/outdated_test.dart + +## Section 0 $ pub outdated --json { "packages": [ @@ -58,6 +61,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub outdated --no-color Showing outdated packages. [*] indicates versions that are not the latest available. @@ -71,6 +77,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 2 $ pub outdated --no-color --no-transitive Showing outdated packages. [*] indicates versions that are not the latest available. @@ -84,6 +93,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 3 $ pub outdated --no-color --up-to-date Showing outdated packages. [*] indicates versions that are not the latest available. @@ -97,6 +109,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 4 $ pub outdated --no-color --prereleases Showing outdated packages. [*] indicates versions that are not the latest available. @@ -110,6 +125,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 5 $ pub outdated --no-color --no-dev-dependencies Showing outdated packages. [*] indicates versions that are not the latest available. @@ -123,6 +141,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 6 $ pub outdated --no-color --no-dependency-overrides Showing outdated packages. [*] indicates versions that are not the latest available. @@ -140,6 +161,9 @@ 1 dependency is constrained to a version that is older than a resolvable version. To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 7 $ pub outdated --no-color --mode=null-safety Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -154,6 +178,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 8 $ pub outdated --no-color --mode=null-safety --transitive Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -168,6 +195,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 9 $ pub outdated --no-color --mode=null-safety --no-prereleases Showing dependencies that are currently not opted in to null-safety. [✗] indicates versions without null safety support. @@ -182,6 +212,9 @@ You are already using the newest resolvable versions listed in the 'Resolvable' column. Newer versions, listed in 'Latest', may not be mutually compatible. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 10 $ pub outdated --json --mode=null-safety { "packages": [ @@ -254,6 +287,9 @@ ] } +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 11 $ pub outdated --json --no-dev-dependencies { "packages": [
diff --git a/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt new file mode 100644 index 0000000..ae304ea --- /dev/null +++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
@@ -0,0 +1,25 @@ +# GENERATED BY: test/upgrade/example_warns_about_major_versions_test.dart + +## Section 0 +$ pub upgrade --major-versions --example +Resolving dependencies... ++ bar 2.0.0 +Changed 1 dependency! + +Changed 1 constraint in pubspec.yaml: + bar: ^1.0.0 -> ^2.0.0 +Resolving dependencies in ./example... +Got dependencies in ./example. +[STDERR] Running `upgrade --major-versions` only in `.`. Run `dart pub upgrade --major-versions --directory example/` separately. + +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 +$ pub upgrade --major-versions --directory example +Resolving dependencies in example... +> foo 2.0.0 (was 1.0.0) +Changed 1 dependency in example! + +Changed 1 constraint in pubspec.yaml: + foo: ^1.0.0 -> ^2.0.0 +
diff --git a/test/goldens/upgrade_null_safety_example.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt similarity index 62% rename from test/goldens/upgrade_null_safety_example.txt rename to test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt index 5c5b31c..cabc0be 100644 --- a/test/goldens/upgrade_null_safety_example.txt +++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt
@@ -1,3 +1,6 @@ +# GENERATED BY: test/upgrade/example_warns_about_major_versions_test.dart + +## Section 0 $ pub upgrade --null-safety --example Resolving dependencies... + bar 2.0.0 @@ -7,8 +10,11 @@ bar: ^1.0.0 -> ^2.0.0 Resolving dependencies in ./example... Got dependencies in ./example. -[ERR] Running `upgrade --null-safety` only in `.`. Run `dart pub upgrade --null-safety --directory example/` separately. +[STDERR] Running `upgrade --null-safety` only in `.`. Run `dart pub upgrade --null-safety --directory example/` separately. +-------------------------------- END OF OUTPUT --------------------------------- + +## Section 1 $ pub upgrade --null-safety --directory example Resolving dependencies in example... > bar 2.0.0 (was 1.0.0)
diff --git a/test/token/add_token_test.dart b/test/token/add_token_test.dart index 8105ce5..ca68c41 100644 --- a/test/token/add_token_test.dart +++ b/test/token/add_token_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -46,7 +44,7 @@ await runPub( args: ['token', 'add', 'https://example.com/', '--env-var', 'TOKEN'], - error: 'Environment variable `TOKEN` is not defined.', + error: 'Environment variable "TOKEN" is not defined.', ); await d.tokensFile({ @@ -68,7 +66,7 @@ await runPub( args: ['token', 'add', 'https://example.com/', '--env-var', 'TOKEN'], environment: {'TOKEN': 'secret'}, - error: isNot(contains('Environment variable TOKEN is not defined.')), + error: isNot(contains('is not defined.')), ); await d.tokensFile({ @@ -135,10 +133,21 @@ await d.dir(configPath).create(); await runPub( args: ['token', 'add', 'http://mypub.com'], - error: contains('Insecure package repository could not be added.'), - exitCode: exit_codes.DATA, + error: contains('insecure repositories cannot use authentication'), + exitCode: exit_codes.USAGE, ); await d.dir(configPath, [d.nothing('pub-tokens.json')]).validate(); }); + + test('with empty environment gives error message', () async { + await runPub( + args: ['token', 'add', 'https://mypub.com'], + input: ['auth-token'], + error: contains('No config dir found.'), + exitCode: exit_codes.DATA, + environment: {'_PUB_TEST_CONFIG_DIR': null}, + includeParentEnvironment: false, + ); + }); }
diff --git a/test/token/error_message_test.dart b/test/token/error_message_test.dart new file mode 100644 index 0000000..53431a5 --- /dev/null +++ b/test/token/error_message_test.dart
@@ -0,0 +1,85 @@ +// Copyright (c) 2021, 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 'package:shelf/shelf.dart' as shelf; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void respondWithWwwAuthenticate(String headerValue) { + globalServer.expect('GET', '/api/packages/versions/new', (request) { + return shelf.Response(403, headers: {'www-authenticate': headerValue}); + }); +} + +Future<void> expectPubErrorMessage(dynamic matcher) { + return runPub( + args: ['lish'], + environment: { + 'PUB_HOSTED_URL': globalServer.url, + '_PUB_TEST_AUTH_METHOD': 'token', + }, + exitCode: 65, + input: ['y'], + error: matcher, + ); +} + +void main() { + setUp(() async { + await d.validPackage.create(); + await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': globalServer.url, 'token': 'access token'}, + ] + }).create(); + }); + + test('prints www-authenticate message', () async { + respondWithWwwAuthenticate('bearer realm="pub", message="custom message"'); + await expectPubErrorMessage(contains('custom message')); + }); + + test('sanitizes and prints dirty www-authenticate message', () { + // Unable to test this case because shelf does not allow characters [1] + // that pub cli supposed to sanitize. + // + // [1] https://github.com/dart-lang/sdk/blob/main/sdk/lib/_http/http_headers.dart#L653-L662 + }); + + test('trims and prints long www-authenticate message', () async { + var message = List.generate(2048, (_) => 'a').join(); + + respondWithWwwAuthenticate('bearer realm="pub", message="$message"'); + await expectPubErrorMessage(allOf( + isNot(contains(message)), + contains(message.substring(0, 1024)), + )); + }); + + test('does not prints message if realm is not equals to pub', () async { + respondWithWwwAuthenticate('bearer realm="web", message="custom message"'); + await expectPubErrorMessage(isNot(contains('custom message'))); + }); + + test('does not prints message if challenge is not equals to bearer', + () async { + respondWithWwwAuthenticate('basic realm="pub", message="custom message"'); + await expectPubErrorMessage(isNot(contains('custom message'))); + }); + + test('prints message for bearer challenge for pub realm only', () async { + respondWithWwwAuthenticate( + 'basic realm="pub", message="enter username and password", ' + 'newAuth message="use web portal to login", ' + 'bearer realm="api", message="contact IT dept to enroll", ' + 'bearer realm="pub", ' + 'bearer realm="pub", message="pub realm message"', + ); + await expectPubErrorMessage(contains('pub realm message')); + }); +}
diff --git a/test/token/remove_token_test.dart b/test/token/remove_token_test.dart index f9ce67d..bfe2428 100644 --- a/test/token/remove_token_test.dart +++ b/test/token/remove_token_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; @@ -61,4 +59,14 @@ await d.dir(configPath, [d.nothing('pub-tokens.json')]).validate(); }); + + test('with empty environment gives error message', () async { + await runPub( + args: ['token', 'remove', 'http://mypub.com'], + error: contains('No config dir found.'), + exitCode: exit_codes.DATA, + environment: {'_PUB_TEST_CONFIG_DIR': null}, + includeParentEnvironment: false, + ); + }); }
diff --git a/test/token/token_authentication_test.dart b/test/token/token_authentication_test.dart new file mode 100644 index 0000000..c020ac0 --- /dev/null +++ b/test/token/token_authentication_test.dart
@@ -0,0 +1,46 @@ +// Copyright (c) 2021, 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 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../lish/utils.dart'; +import '../test_pub.dart'; + +void main() { + setUp(d.validPackage.create); + + test('with a pre existing environment token authenticates', () async { + await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': globalServer.url, 'env': 'TOKEN'}, + ] + }).create(); + var pub = await startPublish(globalServer, + authMethod: 'token', environment: {'TOKEN': 'access token'}); + await confirmPublish(pub); + + handleUploadForm(globalServer); + + await pub.shouldExit(1); + }); + + test('with a pre existing opaque token authenticates', () async { + await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': globalServer.url, 'token': 'access token'}, + ] + }).create(); + var pub = await startPublish(globalServer, authMethod: 'token'); + await confirmPublish(pub); + + handleUploadForm(globalServer); + + await pub.shouldExit(1); + }); +}
diff --git a/test/token/when_receives_401_removes_token_test.dart b/test/token/when_receives_401_removes_token_test.dart new file mode 100644 index 0000000..86c0559 --- /dev/null +++ b/test/token/when_receives_401_removes_token_test.dart
@@ -0,0 +1,33 @@ +// Copyright (c) 2021, 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 'package:shelf/shelf.dart' as shelf; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + setUp(d.validPackage.create); + + test('when receives 401 response removes saved token', () async { + final server = await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': server.url, 'token': 'access token'}, + ] + }).create(); + var pub = await startPublish(server, authMethod: 'token'); + await confirmPublish(pub); + + server.expect('GET', '/api/packages/versions/new', (request) { + return shelf.Response(401); + }); + + await pub.shouldExit(65); + + await d.tokensFile({'version': 1, 'hosted': []}).validate(); + }); +}
diff --git a/test/token/when_receives_403_persists_saved_token_test.dart b/test/token/when_receives_403_persists_saved_token_test.dart new file mode 100644 index 0000000..45fc7a4 --- /dev/null +++ b/test/token/when_receives_403_persists_saved_token_test.dart
@@ -0,0 +1,38 @@ +// Copyright (c) 2021, 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 'package:shelf/shelf.dart' as shelf; +import 'package:test/test.dart'; + +import '../descriptor.dart' as d; +import '../test_pub.dart'; + +void main() { + setUp(d.validPackage.create); + + test('when receives 403 response persists saved token', () async { + final server = await servePackages(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': server.url, 'token': 'access token'}, + ] + }).create(); + var pub = await startPublish(server, authMethod: 'token'); + await confirmPublish(pub); + + server.expect('GET', '/api/packages/versions/new', (request) { + return shelf.Response(403); + }); + + await pub.shouldExit(65); + + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': server.url, 'token': 'access token'}, + ] + }).validate(); + }); +}
diff --git a/test/unknown_source_test.dart b/test/unknown_source_test.dart index 241f9c7..37591d0 100644 --- a/test/unknown_source_test.dart +++ b/test/unknown_source_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:convert'; import 'package:test/test.dart'; @@ -74,7 +72,9 @@ await pubCommand(command); // Should upgrade to the new one. - await d.appPackagesFile({'foo': '../foo'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', path: '../foo'), + ]).validate(); }); }); }
diff --git a/test/upgrade/dry_run_does_not_apply_changes_test.dart b/test/upgrade/dry_run_does_not_apply_changes_test.dart index e77d3b8..8c942ca 100644 --- a/test/upgrade/dry_run_does_not_apply_changes_test.dart +++ b/test/upgrade/dry_run_does_not_apply_changes_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/io.dart'; import 'package:test/test.dart'; @@ -13,10 +11,9 @@ void main() { test('--dry-run: shows report, changes nothing', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0'); // Create the first lockfile. await d.appDir({'foo': '1.0.0'}).create(); @@ -52,10 +49,9 @@ }); test('--dry-run --major-versions: shows report, changes nothing', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0'); await d.appDir({'foo': '^1.0.0'}).create();
diff --git a/test/upgrade/example_warns_about_major_versions_test.dart b/test/upgrade/example_warns_about_major_versions_test.dart index 0813ed2..b5c9a67 100644 --- a/test/upgrade/example_warns_about_major_versions_test.dart +++ b/test/upgrade/example_warns_about_major_versions_test.dart
@@ -2,23 +2,19 @@ // 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. -// @dart = 2.11 - -import 'package:test/test.dart'; - import '../descriptor.dart' as d; import '../golden_file.dart'; import '../test_pub.dart'; void main() { - test( + testWithGolden( 'pub upgrade --major-versions does not update major versions in example/', - () async { - await servePackages((b) => b + (ctx) async { + await servePackages() ..serve('foo', '1.0.0') ..serve('foo', '2.0.0') ..serve('bar', '1.0.0') - ..serve('bar', '2.0.0')); + ..serve('bar', '2.0.0'); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', @@ -36,24 +32,14 @@ ]) ]).create(); - final buffer = StringBuffer(); - await runPubIntoBuffer( - ['upgrade', '--major-versions', '--example'], - buffer, - ); - await runPubIntoBuffer( - ['upgrade', '--major-versions', '--directory', 'example'], - buffer, - ); - - expectMatchesGoldenFile( - buffer.toString(), 'test/goldens/upgrade_major_versions_example.txt'); + await ctx.run(['upgrade', '--major-versions', '--example']); + await ctx.run(['upgrade', '--major-versions', '--directory', 'example']); }); - test( + testWithGolden( 'pub upgrade --null-safety does not update null-safety of dependencies in example/', - () async { - await servePackages((b) => b + (ctx) async { + await servePackages() ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.7.0 <3.0.0'}, }) @@ -65,7 +51,7 @@ }) ..serve('bar', '2.0.0', pubspec: { 'environment': {'sdk': '>=2.12.0 <3.0.0'}, - })); + }); await d.dir(appPath, [ d.pubspec({ 'name': 'myapp', @@ -86,20 +72,14 @@ ]) ]).create(); - final buffer = StringBuffer(); - await runPubIntoBuffer( + await ctx.run( ['upgrade', '--null-safety', '--example'], - buffer, environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}, ); - await runPubIntoBuffer( + await ctx.run( ['upgrade', '--null-safety', '--directory', 'example'], - buffer, environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'}, ); - - expectMatchesGoldenFile( - buffer.toString(), 'test/goldens/upgrade_null_safety_example.txt'); }); }
diff --git a/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart b/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart index dffb433..5638fb9 100644 --- a/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart +++ b/test/upgrade/git/do_not_upgrade_if_unneeded_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:test/test.dart';
diff --git a/test/upgrade/git/upgrade_locked_test.dart b/test/upgrade/git/upgrade_locked_test.dart index 55938de..a8e744f 100644 --- a/test/upgrade/git/upgrade_locked_test.dart +++ b/test/upgrade/git/upgrade_locked_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/upgrade/git/upgrade_one_locked_test.dart b/test/upgrade/git/upgrade_one_locked_test.dart index 14fa010..5c41fa6 100644 --- a/test/upgrade/git/upgrade_one_locked_test.dart +++ b/test/upgrade/git/upgrade_one_locked_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart b/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart index 33f584c..e74a11e 100644 --- a/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart +++ b/test/upgrade/git/upgrade_to_incompatible_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart';
diff --git a/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart b/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart index e1e160f..ae865eb 100644 --- a/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart +++ b/test/upgrade/git/upgrade_to_nonexistent_pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d;
diff --git a/test/upgrade/hosted/unlock_if_necessary_test.dart b/test/upgrade/hosted/unlock_if_necessary_test.dart index 9bd78fb..2707100 100644 --- a/test/upgrade/hosted/unlock_if_necessary_test.dart +++ b/test/upgrade/hosted/unlock_if_necessary_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,24 +11,28 @@ test( "upgrades one locked pub server package's dependencies if it's " 'necessary', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'foo_dep': 'any'}); - builder.serve('foo_dep', '1.0.0'); - }); + final server = await servePackages(); + + server.serve('foo', '1.0.0', deps: {'foo_dep': 'any'}); + server.serve('foo_dep', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0', 'foo_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'foo_dep', version: '1.0.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '2.0.0', deps: {'foo_dep': '>1.0.0'}); - builder.serve('foo_dep', '2.0.0'); - }); + server.serve('foo', '2.0.0', deps: {'foo_dep': '>1.0.0'}); + server.serve('foo_dep', '2.0.0'); await pubUpgrade(args: ['foo']); - await d.appPackagesFile({'foo': '2.0.0', 'foo_dep': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'foo_dep', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/upgrade/hosted/unlock_single_package_test.dart b/test/upgrade/hosted/unlock_single_package_test.dart index ba3d80f..e443a6a 100644 --- a/test/upgrade/hosted/unlock_single_package_test.dart +++ b/test/upgrade/hosted/unlock_single_package_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,37 +9,43 @@ void main() { test('can unlock a single package only in upgrade', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); - builder.serve('bar', '1.0.0'); - }); + final server = await servePackages(); + + server.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); + server.serve('bar', '1.0.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubGet(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); - globalPackageServer.add((builder) { - builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); - builder.serve('bar', '2.0.0'); - }); + server.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); + server.serve('bar', '2.0.0'); // This can't upgrade 'bar' await pubUpgrade(args: ['bar']); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); - + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); // Introducing foo and bar 1.1.0, to show that only 'bar' will be upgraded - globalPackageServer.add((builder) { - builder.serve('foo', '1.1.0', deps: {'bar': '<2.0.0'}); - builder.serve('bar', '1.1.0'); - }); + server.serve('foo', '1.1.0', deps: {'bar': '<2.0.0'}); + server.serve('bar', '1.1.0'); await pubUpgrade(args: ['bar']); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.1.0'}).validate(); - + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.1.0'), + ]).validate(); await pubUpgrade(); - await d.appPackagesFile({'foo': '2.0.0', 'bar': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/upgrade/hosted/upgrade_removed_constraints_test.dart b/test/upgrade/hosted/upgrade_removed_constraints_test.dart index bb73ddc..cf72c07 100644 --- a/test/upgrade/hosted/upgrade_removed_constraints_test.dart +++ b/test/upgrade/hosted/upgrade_removed_constraints_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,24 +9,29 @@ void main() { test('upgrades dependencies whose constraints have been removed', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared_dep': 'any'}); - builder.serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'}); - builder.serve('shared_dep', '1.0.0'); - builder.serve('shared_dep', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared_dep': 'any'}) + ..serve('bar', '1.0.0', deps: {'shared_dep': '<2.0.0'}) + ..serve('shared_dep', '1.0.0') + ..serve('shared_dep', '2.0.0'); await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await pubUpgrade(); - await d.appPackagesFile( - {'foo': '1.0.0', 'bar': '1.0.0', 'shared_dep': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '1.0.0'), + ]).validate(); await d.appDir({'foo': 'any'}).create(); await pubUpgrade(); - await d.appPackagesFile({'foo': '1.0.0', 'shared_dep': '2.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'shared_dep', version: '2.0.0'), + ]).validate(); }); }
diff --git a/test/upgrade/hosted/warn_about_discontinued_test.dart b/test/upgrade/hosted/warn_about_discontinued_test.dart new file mode 100644 index 0000000..ba7fc57 --- /dev/null +++ b/test/upgrade/hosted/warn_about_discontinued_test.dart
@@ -0,0 +1,80 @@ +// Copyright (c) 2021, 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 'package:test/test.dart'; + +import '../../descriptor.dart' as d; +import '../../test_pub.dart'; + +void main() { + test('Warns about discontinued dependencies', () async { + final server = await servePackages() + ..serve('foo', '1.2.3', deps: {'transitive': 'any'}) + ..serve('transitive', '1.0.0'); + await d.appDir({'foo': '1.2.3'}).create(); + await pubGet(); + + server + ..discontinue('foo') + ..discontinue('transitive'); + // We warn only about the direct dependency here: + await pubUpgrade(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued) + transitive 1.0.0 + No dependencies changed. + 1 package is discontinued. +'''); + server.discontinue('foo', replacementText: 'bar'); + // We warn only about the direct dependency here: + await pubUpgrade(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued replaced by bar) + transitive 1.0.0 + No dependencies changed. + 1 package is discontinued. +'''); + }); + + test('Warns about discontinued dev_dependencies', () async { + final server = await servePackages() + ..serve('foo', '1.2.3', deps: {'transitive': 'any'}) + ..serve('transitive', '1.0.0'); + + await d.dir(appPath, [ + d.file('pubspec.yaml', ''' +name: myapp +dependencies: + +dev_dependencies: + foo: 1.2.3 +environment: + sdk: '>=0.1.2 <1.0.0' +''') + ]).create(); + await pubGet(); + + server + ..discontinue('foo') + ..discontinue('transitive'); + + // We warn only about the direct dependency here: + await pubUpgrade(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued) + transitive 1.0.0 + No dependencies changed. + 1 package is discontinued. +'''); + server.discontinue('foo', replacementText: 'bar'); + // We warn only about the direct dependency here: + await pubUpgrade(output: ''' +Resolving dependencies... + foo 1.2.3 (discontinued replaced by bar) + transitive 1.0.0 + No dependencies changed. + 1 package is discontinued. +'''); + }); +}
diff --git a/test/upgrade/renamed_package_circular_dependency.dart b/test/upgrade/renamed_package_circular_dependency.dart index 84ce151..ec10b82 100644 --- a/test/upgrade/renamed_package_circular_dependency.dart +++ b/test/upgrade/renamed_package_circular_dependency.dart
@@ -2,18 +2,15 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; void main() { test('The upgrade report handles a package becoming root', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'myapp': 'any'}); - builder.serve('myapp', '1.0.0', deps: {'foo': 'any'}); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'myapp': 'any'}) + ..serve('myapp', '1.0.0', deps: {'foo': 'any'}); await d.dir(appPath, [ d.pubspec({
diff --git a/test/upgrade/report/describes_change_test.dart b/test/upgrade/report/describes_change_test.dart index 382deb0..96410cb 100644 --- a/test/upgrade/report/describes_change_test.dart +++ b/test/upgrade/report/describes_change_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,11 +9,11 @@ void main() { test('Shows count of discontinued packages', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0'); - }); + final server = await servePackages(); - globalPackageServer.add((builder) => builder..discontinue('foo')); + server.serve('foo', '2.0.0'); + + server.discontinue('foo'); // Create the first lockfile. await d.appDir({'foo': '2.0.0'}).create(); @@ -35,12 +33,11 @@ }); test('shows how package changed from previous lockfile', () async { - await servePackages((builder) { - builder.serve('unchanged', '1.0.0'); - builder.serve('version_changed', '1.0.0'); - builder.serve('version_changed', '2.0.0'); - builder.serve('source_changed', '1.0.0'); - }); + await servePackages() + ..serve('unchanged', '1.0.0') + ..serve('version_changed', '1.0.0') + ..serve('version_changed', '2.0.0') + ..serve('source_changed', '1.0.0'); await d.dir('source_changed', [ d.libDir('source_changed'),
diff --git a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart index 41f90d0..ef987b9 100644 --- a/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart +++ b/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,14 +11,13 @@ test( 'Shows newer versions available for packages that are locked and not being upgraded', () async { - await servePackages((builder) { - builder.serve('not_upgraded', '1.0.0'); - builder.serve('not_upgraded', '2.0.0'); - builder.serve('not_upgraded', '3.0.0-dev'); - builder.serve('upgraded', '1.0.0'); - builder.serve('upgraded', '2.0.0'); - builder.serve('upgraded', '3.0.0-dev'); - }); + await servePackages() + ..serve('not_upgraded', '1.0.0') + ..serve('not_upgraded', '2.0.0') + ..serve('not_upgraded', '3.0.0-dev') + ..serve('upgraded', '1.0.0') + ..serve('upgraded', '2.0.0') + ..serve('upgraded', '3.0.0-dev'); // Constraint everything to the first version. await d.appDir({'not_upgraded': '1.0.0', 'upgraded': '1.0.0'}).create();
diff --git a/test/upgrade/report/highlights_overrides_test.dart b/test/upgrade/report/highlights_overrides_test.dart index 04ae0ba..93f9f3b 100644 --- a/test/upgrade/report/highlights_overrides_test.dart +++ b/test/upgrade/report/highlights_overrides_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,7 +9,8 @@ void main() { test('highlights overridden packages', () async { - await servePackages((builder) => builder.serve('overridden', '1.0.0')); + final server = await servePackages(); + server.serve('overridden', '1.0.0'); await d.dir(appPath, [ d.pubspec({
diff --git a/test/upgrade/report/leading_character_shows_change_test.dart b/test/upgrade/report/leading_character_shows_change_test.dart index e7438d8..88f7ed2 100644 --- a/test/upgrade/report/leading_character_shows_change_test.dart +++ b/test/upgrade/report/leading_character_shows_change_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,17 +9,16 @@ void main() { test('the character before each package describes the change', () async { - await servePackages((builder) { - builder.serve('added', '1.0.0'); - builder.serve('downgraded', '1.0.0'); - builder.serve('downgraded', '2.0.0'); - builder.serve('overridden', '1.0.0'); - builder.serve('removed', '1.0.0'); - builder.serve('source_changed', '1.0.0'); - builder.serve('upgraded', '1.0.0'); - builder.serve('upgraded', '2.0.0'); - builder.serve('unchanged', '1.0.0'); - }); + await servePackages() + ..serve('added', '1.0.0') + ..serve('downgraded', '1.0.0') + ..serve('downgraded', '2.0.0') + ..serve('overridden', '1.0.0') + ..serve('removed', '1.0.0') + ..serve('source_changed', '1.0.0') + ..serve('upgraded', '1.0.0') + ..serve('upgraded', '2.0.0') + ..serve('unchanged', '1.0.0'); await d.dir('description_changed_1', [ d.libDir('description_changed'),
diff --git a/test/upgrade/report/shows_newer_available_versions_test.dart b/test/upgrade/report/shows_newer_available_versions_test.dart index 54c32ad..39d4e1a 100644 --- a/test/upgrade/report/shows_newer_available_versions_test.dart +++ b/test/upgrade/report/shows_newer_available_versions_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,28 +9,26 @@ void main() { test('shows how many newer versions are available', () async { - await servePackages((builder) { - builder.serve('multiple_newer', '1.0.0'); - builder.serve('multiple_newer', '1.0.1-unstable.1'); - builder.serve('multiple_newer', '1.0.1'); - builder.serve('multiple_newer', '1.0.2-unstable.1'); - builder.serve('multiple_newer_stable', '1.0.0'); - builder.serve('multiple_newer_stable', '1.0.1'); - builder.serve('multiple_newer_stable', '1.0.2'); - builder.serve('multiple_newer_unstable', '1.0.0'); - builder.serve('multiple_newer_unstable', '1.0.1-unstable.1'); - builder.serve('multiple_newer_unstable', '1.0.1-unstable.2'); - builder.serve('multiple_newer_unstable2', '1.0.1-unstable.1'); - builder.serve('multiple_newer_unstable2', '1.0.1-unstable.2'); - builder.serve('multiple_newer_unstable2', '1.0.1-unstable.2'); - builder.serve('no_newer', '1.0.0'); - builder.serve('one_newer_unstable', '1.0.0'); - builder.serve('one_newer_unstable', '1.0.1-unstable.1'); - builder.serve('one_newer_unstable2', '1.0.1-unstable.1'); - builder.serve('one_newer_unstable2', '1.0.1-unstable.2'); - builder.serve('one_newer_stable', '1.0.0'); - builder.serve('one_newer_stable', '1.0.1'); - }); + await servePackages() + ..serve('multiple_newer', '1.0.0') + ..serve('multiple_newer', '1.0.1-unstable.1') + ..serve('multiple_newer', '1.0.1') + ..serve('multiple_newer', '1.0.2-unstable.1') + ..serve('multiple_newer_stable', '1.0.0') + ..serve('multiple_newer_stable', '1.0.1') + ..serve('multiple_newer_stable', '1.0.2') + ..serve('multiple_newer_unstable', '1.0.0') + ..serve('multiple_newer_unstable', '1.0.1-unstable.1') + ..serve('multiple_newer_unstable', '1.0.1-unstable.2') + ..serve('multiple_newer_unstable2', '1.0.1-unstable.1') + ..serve('multiple_newer_unstable2', '1.0.1-unstable.2') + ..serve('no_newer', '1.0.0') + ..serve('one_newer_unstable', '1.0.0') + ..serve('one_newer_unstable', '1.0.1-unstable.1') + ..serve('one_newer_unstable2', '1.0.1-unstable.1') + ..serve('one_newer_unstable2', '1.0.1-unstable.2') + ..serve('one_newer_stable', '1.0.0') + ..serve('one_newer_stable', '1.0.1'); // Constraint everything to the first version. await d.appDir({
diff --git a/test/upgrade/report/shows_number_of_changed_dependencies_test.dart b/test/upgrade/report/shows_number_of_changed_dependencies_test.dart index 1c79302..91ba5aa 100644 --- a/test/upgrade/report/shows_number_of_changed_dependencies_test.dart +++ b/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -13,11 +11,10 @@ test( 'does not show how many newer versions are available for ' 'packages that are locked and not being upgraded', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0'); - builder.serve('c', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0') + ..serve('c', '2.0.0'); await d.appDir({'a': 'any'}).create();
diff --git a/test/upgrade/report/shows_pub_outdated_test.dart b/test/upgrade/report/shows_pub_outdated_test.dart index 11d50da..0fdb322 100644 --- a/test/upgrade/report/shows_pub_outdated_test.dart +++ b/test/upgrade/report/shows_pub_outdated_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../../descriptor.dart' as d; @@ -11,24 +9,23 @@ void main() { test('shows pub outdated', () async { - await servePackages((builder) { - builder.serve('multiple_newer', '1.0.0'); - builder.serve('multiple_newer', '1.0.1-unstable.1'); - builder.serve('multiple_newer', '1.0.1'); - builder.serve('multiple_newer', '1.0.2-unstable.1'); - builder.serve('multiple_newer', '1.0.2-unstable.2'); - builder.serve('multiple_newer_stable', '1.0.0'); - builder.serve('multiple_newer_stable', '1.0.1'); - builder.serve('multiple_newer_stable', '1.0.2'); - builder.serve('multiple_newer_unstable', '1.0.0'); - builder.serve('multiple_newer_unstable', '1.0.1-unstable.1'); - builder.serve('multiple_newer_unstable', '1.0.1-unstable.2'); - builder.serve('no_newer', '1.0.0'); - builder.serve('one_newer_unstable', '1.0.0'); - builder.serve('one_newer_unstable', '1.0.1-unstable.1'); - builder.serve('one_newer_stable', '1.0.0'); - builder.serve('one_newer_stable', '1.0.1'); - }); + await servePackages() + ..serve('multiple_newer', '1.0.0') + ..serve('multiple_newer', '1.0.1-unstable.1') + ..serve('multiple_newer', '1.0.1') + ..serve('multiple_newer', '1.0.2-unstable.1') + ..serve('multiple_newer', '1.0.2-unstable.2') + ..serve('multiple_newer_stable', '1.0.0') + ..serve('multiple_newer_stable', '1.0.1') + ..serve('multiple_newer_stable', '1.0.2') + ..serve('multiple_newer_unstable', '1.0.0') + ..serve('multiple_newer_unstable', '1.0.1-unstable.1') + ..serve('multiple_newer_unstable', '1.0.1-unstable.2') + ..serve('no_newer', '1.0.0') + ..serve('one_newer_unstable', '1.0.0') + ..serve('one_newer_unstable', '1.0.1-unstable.1') + ..serve('one_newer_stable', '1.0.0') + ..serve('one_newer_stable', '1.0.1'); // Constraint everything to the first version. await d.appDir({
diff --git a/test/upgrade/upgrade_major_versions_test.dart b/test/upgrade/upgrade_major_versions_test.dart index 7ab389b..c5f0994 100644 --- a/test/upgrade/upgrade_major_versions_test.dart +++ b/test/upgrade/upgrade_major_versions_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -12,14 +10,13 @@ void main() { group('pub upgrade --major-versions', () { test('bumps dependency constraints and shows summary report', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('bar', '0.1.0'); - builder.serve('bar', '0.2.0'); - builder.serve('baz', '1.0.0'); - builder.serve('baz', '1.0.1'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('bar', '0.1.0') + ..serve('bar', '0.2.0') + ..serve('baz', '1.0.0') + ..serve('baz', '1.0.1'); await d.appDir({ 'foo': '^1.0.0', @@ -44,23 +41,21 @@ 'bar': '^0.2.0', 'baz': '^1.0.0', }).validate(); - - await d.appPackagesFile({ - 'foo': '2.0.0', - 'bar': '0.2.0', - 'baz': '1.0.1', - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '0.2.0'), + d.packageConfigEntry(name: 'baz', version: '1.0.1'), + ]).validate(); }); test('bumps dev_dependency constraints and shows summary report', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('bar', '0.1.0'); - builder.serve('bar', '0.2.0'); - builder.serve('baz', '1.0.0'); - builder.serve('baz', '1.0.1'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('bar', '0.1.0') + ..serve('bar', '0.2.0') + ..serve('baz', '1.0.0') + ..serve('baz', '1.0.1'); await d.dir(appPath, [ d.pubspec({ @@ -96,20 +91,18 @@ }), ]).validate(); - await d.appPackagesFile({ - 'foo': '2.0.0', - 'bar': '0.2.0', - 'baz': '1.0.1', - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '0.2.0'), + d.packageConfigEntry(name: 'baz', version: '1.0.1'), + ]).validate(); }); test('upgrades only the selected package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('bar', '0.1.0'); - builder.serve('bar', '0.2.0'); - }); + final server = await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('bar', '0.1.0'); await d.appDir({ 'foo': '^1.0.0', @@ -118,6 +111,8 @@ await pubGet(); + server.serve('bar', '0.1.1'); + // 1 constraint should be updated await pubUpgrade( args: ['--major-versions', 'foo'], @@ -132,15 +127,17 @@ 'bar': '^0.1.0', }).validate(); - await d.appPackagesFile({'foo': '2.0.0', 'bar': '0.1.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '2.0.0'), + d.packageConfigEntry(name: 'bar', version: '0.1.0'), + ]).validate(); }); test('chooses the latest version where possible', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0'); await d.appDir({'foo': '^1.0.0'}).create(); @@ -164,17 +161,17 @@ d.file('pubspec.lock', contains('3.0.0')) ]).validate(); - await d.appPackagesFile({'foo': '3.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '3.0.0'), + ]).validate(); }); test('overridden dependencies - no resolution', () async { - await servePackages( - (builder) => builder - ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'}) - ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) - ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'}) - ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}), - ); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '^2.0.0'}) + ..serve('foo', '2.0.0', deps: {'bar': '^1.0.0'}) + ..serve('bar', '1.0.0', deps: {'foo': '^1.0.0'}) + ..serve('bar', '2.0.0', deps: {'foo': '^2.0.0'}); await d.dir(appPath, [ d.pubspec({ @@ -218,23 +215,25 @@ }) ]).validate(); - await d.appPackagesFile({'foo': '1.0.0', 'bar': '1.0.0'}).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '1.0.0'), + ]).validate(); }); test('upgrade should not downgrade any versions', () async { /// The version solver solves the packages with the least number of /// versions remaining, so we add more 'bar' packages to force 'foo' to be /// resolved first - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0', pubspec: { 'dependencies': {'bar': '1.0.0'} - }); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '2.0.0'); - builder.serve('bar', '3.0.0'); - builder.serve('bar', '4.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('bar', '2.0.0') + ..serve('bar', '3.0.0') + ..serve('bar', '4.0.0'); await d.appDir({ 'foo': '^1.0.0', @@ -257,10 +256,10 @@ 'bar': '^4.0.0', }).validate(); - await d.appPackagesFile({ - 'foo': '1.0.0', - 'bar': '4.0.0', - }).validate(); + await d.appPackageConfigFile([ + d.packageConfigEntry(name: 'foo', version: '1.0.0'), + d.packageConfigEntry(name: 'bar', version: '4.0.0'), + ]).validate(); }); }); }
diff --git a/test/upgrade/upgrade_null_safety_test.dart b/test/upgrade/upgrade_null_safety_test.dart index 9c7dad0..557c589 100644 --- a/test/upgrade/upgrade_null_safety_test.dart +++ b/test/upgrade/upgrade_null_safety_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; @@ -11,29 +9,28 @@ void main() { group('pub upgrade --null-safety', () { setUp(() async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.10.0<3.0.0'}, - }); - builder.serve('foo', '2.0.0', pubspec: { + }) + ..serve('foo', '2.0.0', pubspec: { 'environment': {'sdk': '>=2.12.0<3.0.0'}, - }); - builder.serve('bar', '1.0.0', pubspec: { + }) + ..serve('bar', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0<3.0.0'}, - }); - builder.serve('bar', '2.0.0-nullsafety.0', pubspec: { + }) + ..serve('bar', '2.0.0-nullsafety.0', pubspec: { 'environment': {'sdk': '>=2.12.0<3.0.0'}, - }); - builder.serve('baz', '1.0.0', pubspec: { + }) + ..serve('baz', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0<3.0.0'}, - }); - builder.serve('has_conflict', '1.0.0', pubspec: { + }) + ..serve('has_conflict', '1.0.0', pubspec: { 'environment': {'sdk': '>=2.9.0<3.0.0'}, - }); - builder.serve('has_conflict', '2.0.0', pubspec: { + }) + ..serve('has_conflict', '2.0.0', pubspec: { 'environment': {'sdk': '>=2.13.0<3.0.0'}, }); - }); }); test('upgrades to null-safety versions', () async {
diff --git a/test/validator/changelog_test.dart b/test/validator/changelog_test.dart index be166c3..5bef662 100644 --- a/test/validator/changelog_test.dart +++ b/test/validator/changelog_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/changelog.dart';
diff --git a/test/validator/compiled_dartdoc_test.dart b/test/validator/compiled_dartdoc_test.dart index a656958..f1d3d6d 100644 --- a/test/validator/compiled_dartdoc_test.dart +++ b/test/validator/compiled_dartdoc_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/compiled_dartdoc.dart';
diff --git a/test/validator/dependency_override_test.dart b/test/validator/dependency_override_test.dart index f459119..21a437d 100644 --- a/test/validator/dependency_override_test.dart +++ b/test/validator/dependency_override_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/dependency_override.dart';
diff --git a/test/validator/dependency_test.dart b/test/validator/dependency_test.dart index 00ab0c3..db9db15 100644 --- a/test/validator/dependency_test.dart +++ b/test/validator/dependency_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:convert'; @@ -29,7 +27,7 @@ /// Sets up a test package with dependency [dep] and mocks a server with /// [hostedVersions] of the package available. -Future setUpDependency(Map dep, {List<String> hostedVersions}) { +Future setUpDependency(Map dep, {List<String>? hostedVersions}) { useMockClient(MockClient((request) { expect(request.method, equals('GET')); expect(request.url.path, equals('/api/packages/foo'));
diff --git a/test/validator/deprecated_fields_test.dart b/test/validator/deprecated_fields_test.dart index a13774b..ee4551d 100644 --- a/test/validator/deprecated_fields_test.dart +++ b/test/validator/deprecated_fields_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/deprecated_fields.dart';
diff --git a/test/validator/directory_test.dart b/test/validator/directory_test.dart index 5a5ec99..7cc53b6 100644 --- a/test/validator/directory_test.dart +++ b/test/validator/directory_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/directory.dart';
diff --git a/test/validator/executable_test.dart b/test/validator/executable_test.dart index 555f768..d9973e7 100644 --- a/test/validator/executable_test.dart +++ b/test/validator/executable_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/executable.dart';
diff --git a/test/validator/flutter_constraint_test.dart b/test/validator/flutter_constraint_test.dart index 685c59d..b7bdf7c 100644 --- a/test/validator/flutter_constraint_test.dart +++ b/test/validator/flutter_constraint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -20,7 +18,7 @@ } Future<void> setup({ - String flutterConstraint, + String? flutterConstraint, }) async { final fakeFlutterRoot = d.dir('fake_flutter_root', [d.file('version', '1.23.0')]);
diff --git a/test/validator/flutter_plugin_format_test.dart b/test/validator/flutter_plugin_format_test.dart index cddeaf9..0c24bda 100644 --- a/test/validator/flutter_plugin_format_test.dart +++ b/test/validator/flutter_plugin_format_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/flutter_plugin_format.dart';
diff --git a/test/validator/gitignore_test.dart b/test/validator/gitignore_test.dart index d6140f5..f7b02fe 100644 --- a/test/validator/gitignore_test.dart +++ b/test/validator/gitignore_test.dart
@@ -2,20 +2,25 @@ // 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. -// @dart=2.10 +import 'dart:io'; +import 'package:path/path.dart' as p; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; import '../descriptor.dart' as d; import '../test_pub.dart'; -Future<void> expectValidation(error, int exitCode) async { +Future<void> expectValidation( + error, + int exitCode, { + String? workingDirectory, +}) async { await runPub( error: error, args: ['publish', '--dry-run'], environment: {'_PUB_TEST_SDK_VERSION': '2.12.0'}, - workingDirectory: d.path(appPath), + workingDirectory: workingDirectory ?? d.path(appPath), exitCode: exitCode, ); } @@ -46,4 +51,55 @@ ]), exit_codes.DATA); }); + + test('Should also consider gitignores from above the package root', () async { + await d.git('reporoot', [ + d.dir( + 'myapp', + [ + d.file('foo.txt'), + ...d.validPackage.contents, + ], + ), + ]).create(); + final packageRoot = p.join(d.sandbox, 'reporoot', 'myapp'); + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}, + workingDirectory: packageRoot); + + await expectValidation(contains('Package has 0 warnings.'), 0, + workingDirectory: packageRoot); + + await d.dir('reporoot', [ + d.file('.gitignore', '*.txt'), + ]).create(); + + await expectValidation( + allOf([ + contains('Package has 1 warning.'), + contains('foo.txt'), + contains( + 'Consider adjusting your `.gitignore` files to not ignore those files'), + ]), + exit_codes.DATA, + workingDirectory: packageRoot); + }); + + test('Should not follow symlinks', () async { + await d.git('myapp', [ + ...d.validPackage.contents, + ]).create(); + final packageRoot = p.join(d.sandbox, 'myapp'); + await pubGet( + environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'}, + workingDirectory: packageRoot); + + Link(p.join(packageRoot, '.abc', 'itself')).createSync( + packageRoot, + recursive: true, + ); + + await expectValidation(contains('Package has 0 warnings.'), 0, + workingDirectory: packageRoot); + }); }
diff --git a/test/validator/language_version_test.dart b/test/validator/language_version_test.dart index 37431d4..39c9465 100644 --- a/test/validator/language_version_test.dart +++ b/test/validator/language_version_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/language_version.dart'; @@ -17,7 +15,7 @@ LanguageVersionValidator(entrypoint); Future<void> setup( - {String sdkConstraint, String libraryLanguageVersion}) async { + {required String sdkConstraint, String? libraryLanguageVersion}) async { await d.validPackage.create(); await d.dir(appPath, [ d.pubspec({
diff --git a/test/validator/leak_detection_test.dart b/test/validator/leak_detection_test.dart index ee7d5d3..c055e59 100644 --- a/test/validator/leak_detection_test.dart +++ b/test/validator/leak_detection_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/leak_detection.dart';
diff --git a/test/validator/license_test.dart b/test/validator/license_test.dart index 77225b5..8717c75 100644 --- a/test/validator/license_test.dart +++ b/test/validator/license_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/io.dart';
diff --git a/test/validator/name_test.dart b/test/validator/name_test.dart index 5639c09..7cbb51c 100644 --- a/test/validator/name_test.dart +++ b/test/validator/name_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/io.dart';
diff --git a/test/validator/null_safety_mixed_mode_test.dart b/test/validator/null_safety_mixed_mode_test.dart index 6ec4746..d62d051 100644 --- a/test/validator/null_safety_mixed_mode_test.dart +++ b/test/validator/null_safety_mixed_mode_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -20,7 +18,7 @@ } Future<void> setup({ - String sdkConstraint, + required String sdkConstraint, Map dependencies = const {}, Map devDependencies = const {}, List<d.Descriptor> extraFiles = const [], @@ -47,14 +45,13 @@ group('should consider a package valid if it', () { test('is not opting in to null-safety, but depends on package that is', () async { - await servePackages( - (server) => server.serve( - 'foo', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'foo', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await setup( @@ -63,14 +60,13 @@ }); test('is opting in to null-safety and depends on package that is', () async { - await servePackages( - (server) => server.serve( - 'foo', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'foo', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await setup( @@ -80,14 +76,13 @@ test('is opting in to null-safety has dev_dependency that is not', () async { - await servePackages( - (server) => server.serve( - 'foo', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'foo', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.12.0 <3.0.0', devDependencies: { @@ -100,14 +95,13 @@ group('should consider a package invalid if it', () { test('is opting in to null-safety, but depends on package that is not', () async { - await servePackages( - (server) => server.serve( - 'foo', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'foo', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, ); await setup( @@ -136,17 +130,16 @@ test( 'is opting in to null-safety, but depends on package has file opting out', () async { - await servePackages( - (server) => server.serve('foo', '0.0.1', pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, contents: [ - d.dir('lib', [ - d.file('foo.dart', ''' + final server = await servePackages(); + server.serve('foo', '0.0.1', pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, contents: [ + d.dir('lib', [ + d.file('foo.dart', ''' // @dart = 2.9 ''') - ]) - ]), - ); + ]) + ]); await setup( sdkConstraint: '>=2.12.0 <3.0.0', dependencies: {'foo': '^0.0.1'});
diff --git a/test/validator/pubspec_field_test.dart b/test/validator/pubspec_field_test.dart index 7d4dbd7..8e6fefc 100644 --- a/test/validator/pubspec_field_test.dart +++ b/test/validator/pubspec_field_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/pubspec_field.dart'; @@ -57,7 +55,7 @@ test('has executables', () async { var pkg = packageMap('test_pkg', '1.0.0'); - pkg['executables'] = <String, String>{ + pkg['executables'] = <String, String?>{ 'test_pkg': null, 'test_pkg_helper': 'helper', };
diff --git a/test/validator/pubspec_test.dart b/test/validator/pubspec_test.dart index 0d964ce..9942220 100644 --- a/test/validator/pubspec_test.dart +++ b/test/validator/pubspec_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/validator/pubspec.dart'; import 'package:test/test.dart';
diff --git a/test/validator/pubspec_typo_test.dart b/test/validator/pubspec_typo_test.dart index efc731b..ab2a547 100644 --- a/test/validator/pubspec_typo_test.dart +++ b/test/validator/pubspec_typo_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/pubspec_typo.dart';
diff --git a/test/validator/readme_test.dart b/test/validator/readme_test.dart index 132ff6c..6519c6f 100644 --- a/test/validator/readme_test.dart +++ b/test/validator/readme_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as p; import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/io.dart';
diff --git a/test/validator/relative_version_numbering_test.dart b/test/validator/relative_version_numbering_test.dart index 0a9a1f7..2f3da5c 100644 --- a/test/validator/relative_version_numbering_test.dart +++ b/test/validator/relative_version_numbering_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/relative_version_numbering.dart'; @@ -15,10 +13,10 @@ Validator validator(Entrypoint entrypoint) => RelativeVersionNumberingValidator( entrypoint, - Uri.parse(globalPackageServer.url), + Uri.parse(globalServer.url), ); -Future<void> setup({String sdkConstraint}) async { +Future<void> setup({required String sdkConstraint}) async { await d.validPackage.create(); await d.dir(appPath, [ d.pubspec({ @@ -35,14 +33,13 @@ group('should consider a package valid if it', () { test('is not opting in to null-safety with previous non-null-safe version', () async { - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); @@ -52,23 +49,21 @@ test( 'is not opting in to null-safety with previous non-null-safe version. ' 'Even with a later null-safe version', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.0', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '2.0.0', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); await expectValidation(validator); @@ -76,14 +71,13 @@ test('is opting in to null-safety with previous null-safe version', () async { - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); @@ -93,14 +87,13 @@ test( 'is opting in to null-safety using a pre-release of 2.12.0 ' 'with previous null-safe version', () async { - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.12.0-dev <3.0.0'); @@ -110,23 +103,21 @@ test( 'is opting in to null-safety with previous null-safe version. ' 'Even with a later non-null-safe version', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '2.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); await expectValidation(validator); @@ -134,13 +125,13 @@ test('is opting in to null-safety with no existing versions', () async { await setup(sdkConstraint: '>=2.12.0 <3.0.0'); - await servePackages((x) => x); + await servePackages(); await expectValidation(validator); }); test('is not opting in to null-safety with no existing versions', () async { await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await servePackages((x) => x); + await servePackages(); await expectValidation(validator); }); @@ -148,23 +139,21 @@ test( 'is not opting in to null-safety with previous null-safe stable version. ' 'With an in-between not null-safe prerelease', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); await expectValidation(validator); @@ -173,23 +162,21 @@ test( 'opts in to null-safety, with previous stable version not-null-safe. ' 'With an in-between non-null-safe prerelease', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); await expectValidation(validator); @@ -199,14 +186,13 @@ group('should warn if ', () { test('opts in to null-safety, with previous version not-null-safe', () async { - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); @@ -217,14 +203,13 @@ 'is not opting in to null-safety with no existing stable versions. ' 'With a previous in-between null-safe prerelease', () async { await setup(sdkConstraint: '>=2.9.0 <3.0.0'); - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await expectValidation(validator, hints: isNotEmpty); @@ -232,23 +217,21 @@ test( 'is not opting in to null-safety with previous non-null-safe stable version. ' 'With an in-between null-safe prerelease', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); await expectValidation(validator, hints: isNotEmpty); @@ -257,23 +240,21 @@ test( 'opts in to null-safety, with previous version not-null-safe. ' 'Even with a later null-safe version', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.0', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '2.0.0', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); await expectValidation(validator, hints: isNotEmpty); @@ -281,14 +262,13 @@ test('is not opting in to null-safety with previous null-safe version', () async { - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); @@ -298,23 +278,21 @@ test( 'is not opting in to null-safety with previous null-safe version. ' 'Even with a later non-null-safe version', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '2.0.0', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '2.0.0', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.9.0 <3.0.0'); await expectValidation(validator, hints: isNotEmpty); @@ -323,23 +301,21 @@ test( 'is opting in to null-safety with previous null-safe stable version. ' 'with an in-between non-null-safe prerelease', () async { - await servePackages( - (server) => server - ..serve( - 'test_pkg', - '0.0.1', - pubspec: { - 'environment': {'sdk': '>=2.12.0<3.0.0'} - }, - ) - ..serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), - ); + await servePackages() + ..serve( + 'test_pkg', + '0.0.1', + pubspec: { + 'environment': {'sdk': '>=2.12.0<3.0.0'} + }, + ) + ..serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, + ); await setup(sdkConstraint: '>=2.12.0 <3.0.0'); await expectValidation(validator, hints: isNotEmpty); @@ -349,14 +325,13 @@ 'is opting in to null-safety with no existing stable versions. ' 'With a previous non-null-safe prerelease', () async { await setup(sdkConstraint: '>=2.12.0 <3.0.0'); - await servePackages( - (server) => server.serve( - 'test_pkg', - '0.0.2-dev', - pubspec: { - 'environment': {'sdk': '>=2.9.0<3.0.0'} - }, - ), + final server = await servePackages(); + server.serve( + 'test_pkg', + '0.0.2-dev', + pubspec: { + 'environment': {'sdk': '>=2.9.0<3.0.0'} + }, ); await expectValidation(validator, hints: isNotEmpty); });
diff --git a/test/validator/sdk_constraint_test.dart b/test/validator/sdk_constraint_test.dart index 1310d17..c24adf2 100644 --- a/test/validator/sdk_constraint_test.dart +++ b/test/validator/sdk_constraint_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; import 'package:pub/src/validator/sdk_constraint.dart';
diff --git a/test/validator/size_test.dart b/test/validator/size_test.dart index 37a746d..3a22e60 100644 --- a/test/validator/size_test.dart +++ b/test/validator/size_test.dart
@@ -2,10 +2,7 @@ // 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. -// @dart=2.10 - import 'dart:async'; -import 'dart:math' as math; import 'package:pub/src/validator/size.dart'; import 'package:test/test.dart'; @@ -20,7 +17,7 @@ Future<void> expectSizeValidationError(Matcher matcher) async { await expectValidation( - size(100 * math.pow(2, 20) + 1), + size(100 * 1048577 /*2^20 +1*/), errors: contains(matcher), ); } @@ -30,7 +27,7 @@ await d.validPackage.create(); await expectValidation(size(100)); - await expectValidation(size(100 * math.pow(2, 20))); + await expectValidation(size(100 * 1048576 /*2^20*/)); }); group('considers a package invalid if it is more than 100 MB', () {
diff --git a/test/validator/strict_dependencies_test.dart b/test/validator/strict_dependencies_test.dart index 0456413..7b7962a 100644 --- a/test/validator/strict_dependencies_test.dart +++ b/test/validator/strict_dependencies_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:path/path.dart' as path; import 'package:pub/src/entrypoint.dart'; import 'package:pub/src/validator.dart'; @@ -67,8 +65,8 @@ for (var port in ['import', 'export']) { for (var isDev in [false, true]) { - Map<String, String> deps; - Map<String, String> devDeps; + Map<String, String>? deps; + Map<String, String>? devDeps; if (isDev) { devDeps = {'silly_monkey': '^1.2.3'};
diff --git a/test/validator/utils.dart b/test/validator/utils.dart index 7eda0fd..5123683 100644 --- a/test/validator/utils.dart +++ b/test/validator/utils.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'package:test/test.dart'; import '../test_pub.dart';
diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index d9ea6a0..d36a16f 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - import 'dart:async'; import 'dart:io'; @@ -31,6 +29,8 @@ group('override', override); group('downgrade', downgrade); group('features', features, skip: true); + + group('regressions', regressions); } void basicGraph() { @@ -40,14 +40,13 @@ }); test('simple dependency tree', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'aa': '1.0.0', 'ab': '1.0.0'}); - builder.serve('aa', '1.0.0'); - builder.serve('ab', '1.0.0'); - builder.serve('b', '1.0.0', deps: {'ba': '1.0.0', 'bb': '1.0.0'}); - builder.serve('ba', '1.0.0'); - builder.serve('bb', '1.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'aa': '1.0.0', 'ab': '1.0.0'}) + ..serve('aa', '1.0.0') + ..serve('ab', '1.0.0') + ..serve('b', '1.0.0', deps: {'ba': '1.0.0', 'bb': '1.0.0'}) + ..serve('ba', '1.0.0') + ..serve('bb', '1.0.0'); await d.appDir({'a': '1.0.0', 'b': '1.0.0'}).create(); await expectResolves(result: { @@ -61,15 +60,14 @@ }); test('shared dependency with overlapping constraints', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'shared': '>=2.0.0 <4.0.0'}); - builder.serve('b', '1.0.0', deps: {'shared': '>=3.0.0 <5.0.0'}); - builder.serve('shared', '2.0.0'); - builder.serve('shared', '3.0.0'); - builder.serve('shared', '3.6.9'); - builder.serve('shared', '4.0.0'); - builder.serve('shared', '5.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'shared': '>=2.0.0 <4.0.0'}) + ..serve('b', '1.0.0', deps: {'shared': '>=3.0.0 <5.0.0'}) + ..serve('shared', '2.0.0') + ..serve('shared', '3.0.0') + ..serve('shared', '3.6.9') + ..serve('shared', '4.0.0') + ..serve('shared', '5.0.0'); await d.appDir({'a': '1.0.0', 'b': '1.0.0'}).create(); await expectResolves( @@ -79,16 +77,15 @@ test( 'shared dependency where dependent version in turn affects other ' 'dependencies', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.0.1', deps: {'bang': '1.0.0'}); - builder.serve('foo', '1.0.2', deps: {'whoop': '1.0.0'}); - builder.serve('foo', '1.0.3', deps: {'zoop': '1.0.0'}); - builder.serve('bar', '1.0.0', deps: {'foo': '<=1.0.1'}); - builder.serve('bang', '1.0.0'); - builder.serve('whoop', '1.0.0'); - builder.serve('zoop', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.0.1', deps: {'bang': '1.0.0'}) + ..serve('foo', '1.0.2', deps: {'whoop': '1.0.0'}) + ..serve('foo', '1.0.3', deps: {'zoop': '1.0.0'}) + ..serve('bar', '1.0.0', deps: {'foo': '<=1.0.1'}) + ..serve('bang', '1.0.0') + ..serve('whoop', '1.0.0') + ..serve('zoop', '1.0.0'); await d.appDir({'foo': '<=1.0.2', 'bar': '1.0.0'}).create(); await expectResolves( @@ -96,23 +93,21 @@ }); test('circular dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('bar', '1.0.0', deps: {'foo': '1.0.0'}); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('bar', '1.0.0', deps: {'foo': '1.0.0'}); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}); }); test('removed dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '2.0.0', deps: {'baz': '1.0.0'}); - builder.serve('baz', '1.0.0', deps: {'foo': '2.0.0'}); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('bar', '1.0.0') + ..serve('bar', '2.0.0', deps: {'baz': '1.0.0'}) + ..serve('baz', '1.0.0', deps: {'foo': '2.0.0'}); await d.appDir({'foo': '1.0.0', 'bar': 'any'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}, tries: 2); @@ -121,14 +116,13 @@ void withLockFile() { test('with compatible locked dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'}); - builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.0.1'); - builder.serve('bar', '1.0.2'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'}) + ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'}) + ..serve('bar', '1.0.0') + ..serve('bar', '1.0.1') + ..serve('bar', '1.0.2'); await d.appDir({'foo': '1.0.1'}).create(); await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'}); @@ -138,14 +132,13 @@ }); test('with incompatible locked dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'}); - builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.0.1'); - builder.serve('bar', '1.0.2'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'}) + ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'}) + ..serve('bar', '1.0.0') + ..serve('bar', '1.0.1') + ..serve('bar', '1.0.2'); await d.appDir({'foo': '1.0.1'}).create(); await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'}); @@ -155,15 +148,14 @@ }); test('with unrelated locked dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'}); - builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.0.1'); - builder.serve('bar', '1.0.2'); - builder.serve('baz', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'}) + ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'}) + ..serve('bar', '1.0.0') + ..serve('bar', '1.0.1') + ..serve('bar', '1.0.2') + ..serve('baz', '1.0.0'); await d.appDir({'baz': '1.0.0'}).create(); await expectResolves(result: {'baz': '1.0.0'}); @@ -175,17 +167,16 @@ test( 'unlocks dependencies if necessary to ensure that a new ' 'dependency is satisfied', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}); - builder.serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}); - builder.serve('baz', '1.0.0', deps: {'qux': '<2.0.0'}); - builder.serve('qux', '1.0.0'); - builder.serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}); - builder.serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}); - builder.serve('baz', '2.0.0', deps: {'qux': '<3.0.0'}); - builder.serve('qux', '2.0.0'); - builder.serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'}); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '<2.0.0'}) + ..serve('bar', '1.0.0', deps: {'baz': '<2.0.0'}) + ..serve('baz', '1.0.0', deps: {'qux': '<2.0.0'}) + ..serve('qux', '1.0.0') + ..serve('foo', '2.0.0', deps: {'bar': '<3.0.0'}) + ..serve('bar', '2.0.0', deps: {'baz': '<3.0.0'}) + ..serve('baz', '2.0.0', deps: {'qux': '<3.0.0'}) + ..serve('qux', '2.0.0') + ..serve('newdep', '2.0.0', deps: {'baz': '>=1.5.0'}); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: { @@ -209,11 +200,10 @@ test( "produces a nice message for a locked dependency that's the only " 'version of its package', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '>=2.0.0'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '>=2.0.0'}) + ..serve('bar', '1.0.0') + ..serve('bar', '2.0.0'); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '2.0.0'}); @@ -229,30 +219,27 @@ void rootDependency() { test('with root source', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'myapp': 'any'}); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', deps: {'myapp': 'any'}); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0'}); }); test('with mismatched sources', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'myapp': 'any'}); - builder.serve('bar', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'myapp': 'any'}) + ..serve('bar', '1.0.0', deps: { 'myapp': {'git': 'http://nowhere.com/'} }); - }); await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}); }); test('with wrong version', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'myapp': '>0.0.0'}); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', deps: {'myapp': '>0.0.0'}); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -265,10 +252,9 @@ void devDependency() { test("includes root package's dev dependencies", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -281,10 +267,9 @@ }); test("includes dev dependency's transitive dependencies", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -297,10 +282,9 @@ }); test("ignores transitive dependency's dev dependencies", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'dev_dependencies': {'bar': '1.0.0'} - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'dev_dependencies': {'bar': '1.0.0'} }); await d.appDir({'foo': '1.0.0'}).create(); @@ -309,11 +293,10 @@ group('with both a dev and regular dependency', () { test('succeeds when both are satisfied', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -327,9 +310,8 @@ }); test("fails when main dependency isn't satisfied", () async { - await servePackages((builder) { - builder.serve('foo', '3.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -347,9 +329,8 @@ }); test("fails when dev dependency isn't satisfied", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -367,9 +348,8 @@ }); test('fails when dev and main constraints are incompatible', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -386,9 +366,8 @@ }); test('fails when dev and main sources are incompatible', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -407,9 +386,8 @@ }); test('fails when dev and main descriptions are incompatible', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -433,10 +411,9 @@ void unsolvable() { test('no version that matches constraint', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0'); - builder.serve('foo', '2.1.3'); - }); + await servePackages() + ..serve('foo', '2.0.0') + ..serve('foo', '2.1.3'); await d.appDir({'foo': '>=1.0.0 <2.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(""" @@ -446,12 +423,11 @@ }); test('no version that matches combined constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared': '>=2.0.0 <3.0.0'}); - builder.serve('bar', '1.0.0', deps: {'shared': '>=2.9.0 <4.0.0'}); - builder.serve('shared', '2.5.0'); - builder.serve('shared', '3.5.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared': '>=2.0.0 <3.0.0'}) + ..serve('bar', '1.0.0', deps: {'shared': '>=2.9.0 <4.0.0'}) + ..serve('shared', '2.5.0') + ..serve('shared', '3.5.0'); await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -466,12 +442,11 @@ }); test('disjoint constraints', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared': '<=2.0.0'}); - builder.serve('bar', '1.0.0', deps: {'shared': '>3.0.0'}); - builder.serve('shared', '2.0.0'); - builder.serve('shared', '4.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared': '<=2.0.0'}) + ..serve('bar', '1.0.0', deps: {'shared': '>3.0.0'}) + ..serve('shared', '2.0.0') + ..serve('shared', '4.0.0'); await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -483,20 +458,18 @@ }); test('mismatched descriptions', () async { - var otherServer = await PackageServer.start((builder) { - builder.serve('shared', '1.0.0'); - }); + var otherServer = await startPackageServer(); + otherServer.serve('shared', '1.0.0'); - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared': '1.0.0'}); - builder.serve('bar', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared': '1.0.0'}) + ..serve('bar', '1.0.0', deps: { 'shared': { 'hosted': {'name': 'shared', 'url': otherServer.url}, 'version': '1.0.0' } - }); - builder.serve('shared', '1.0.0'); - }); + }) + ..serve('shared', '1.0.0'); await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create(); @@ -515,13 +488,12 @@ test('mismatched sources', () async { await d.dir('shared', [d.libPubspec('shared', '1.0.0')]).create(); - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'shared': '1.0.0'}); - builder.serve('bar', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'shared': '1.0.0'}) + ..serve('bar', '1.0.0', deps: { 'shared': {'path': p.join(d.sandbox, 'shared')} - }); - builder.serve('shared', '1.0.0'); - }); + }) + ..serve('shared', '1.0.0'); await d.appDir({'foo': '1.0.0', 'bar': '1.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -534,12 +506,11 @@ }); test('no valid solution', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'b': '1.0.0'}); - builder.serve('a', '2.0.0', deps: {'b': '2.0.0'}); - builder.serve('b', '1.0.0', deps: {'a': '2.0.0'}); - builder.serve('b', '2.0.0', deps: {'a': '1.0.0'}); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'b': '1.0.0'}) + ..serve('a', '2.0.0', deps: {'b': '2.0.0'}) + ..serve('b', '1.0.0', deps: {'a': '2.0.0'}) + ..serve('b', '2.0.0', deps: {'a': '1.0.0'}); await d.appDir({'a': 'any', 'b': 'any'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -554,10 +525,9 @@ // This is a regression test for #15550. test('no version that matches while backtracking', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0'); await d.appDir({'a': 'any', 'b': '>1.0.0'}).create(); await expectResolves(error: equalsIgnoringWhitespace(""" @@ -568,19 +538,18 @@ // This is a regression test for #18300. test('issue 18300', () async { - await servePackages((builder) { - builder.serve('analyzer', '0.12.2'); - builder.serve('angular', '0.10.0', - deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}); - builder.serve('angular', '0.9.11', - deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}); - builder.serve('angular', '0.9.10', - deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}); - builder.serve('collection', '0.9.0'); - builder.serve('collection', '0.9.1'); - builder.serve('di', '0.0.37', deps: {'analyzer': '>=0.13.0 <0.14.0'}); - builder.serve('di', '0.0.36', deps: {'analyzer': '>=0.13.0 <0.14.0'}); - }); + await servePackages() + ..serve('analyzer', '0.12.2') + ..serve('angular', '0.10.0', + deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}) + ..serve('angular', '0.9.11', + deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}) + ..serve('angular', '0.9.10', + deps: {'di': '>=0.0.32 <0.1.0', 'collection': '>=0.9.1 <1.0.0'}) + ..serve('collection', '0.9.0') + ..serve('collection', '0.9.1') + ..serve('di', '0.0.37', deps: {'analyzer': '>=0.13.0 <0.14.0'}) + ..serve('di', '0.0.36', deps: {'analyzer': '>=0.13.0 <0.14.0'}); await d.appDir({'angular': 'any', 'collection': 'any'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -620,42 +589,40 @@ }); test('fail if all versions have bad source in dep', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: { 'bar': {'bad': 'any'} - }); - builder.serve('foo', '1.0.1', deps: { + }) + ..serve('foo', '1.0.1', deps: { 'baz': {'bad': 'any'} - }); - builder.serve('foo', '1.0.2', deps: { + }) + ..serve('foo', '1.0.2', deps: { 'bang': {'bad': 'any'} }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' Because foo <1.0.1 depends on bar from unknown source "bad", foo <1.0.1 is forbidden. - And because foo >=1.0.1 <1.0.2 depends on baz any from bad, foo <1.0.2 - requires baz any from bad. + And because foo >=1.0.1 <1.0.2 depends on baz from bad, foo <1.0.2 + requires baz from bad. And because baz comes from unknown source "bad" and foo >=1.0.2 depends on - bang any from bad, every version of foo requires bang any from bad. - So, because bang comes from unknown source "bad" and myapp depends on foo - any, version solving failed. + bang from bad, every version of foo requires bang from bad. + So, because bang comes from unknown source "bad" and myapp depends on foo any, + version solving failed. '''), tries: 3); }); test('ignore versions with bad source in dep', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('foo', '1.0.1', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('foo', '1.0.1', deps: { 'bar': {'bad': 'any'} - }); - builder.serve('foo', '1.0.2', deps: { + }) + ..serve('foo', '1.0.2', deps: { 'bar': {'bad': 'any'} - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}, tries: 2); @@ -663,11 +630,10 @@ // Issue 1853 test('reports a nice error across a collapsed cause', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - builder.serve('baz', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('bar', '1.0.0', deps: {'baz': 'any'}) + ..serve('baz', '1.0.0'); await d.dir('baz', [d.libPubspec('baz', '1.0.0')]).create(); await d.appDir({ @@ -685,28 +651,24 @@ void backtracking() { test('circular dependency on older version', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '2.0.0', deps: {'b': '1.0.0'}); - builder.serve('b', '1.0.0', deps: {'a': '1.0.0'}); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '2.0.0', deps: {'b': '1.0.0'}) + ..serve('b', '1.0.0', deps: {'a': '1.0.0'}); await d.appDir({'a': '>=1.0.0'}).create(); await expectResolves(result: {'a': '1.0.0'}, tries: 2); }); test('diamond dependency graph', () async { - await servePackages((builder) { - builder.serve('a', '2.0.0', deps: {'c': '^1.0.0'}); - builder.serve('a', '1.0.0'); - - builder.serve('b', '2.0.0', deps: {'c': '^3.0.0'}); - builder.serve('b', '1.0.0', deps: {'c': '^2.0.0'}); - - builder.serve('c', '3.0.0'); - builder.serve('c', '2.0.0'); - builder.serve('c', '1.0.0'); - }); + await servePackages() + ..serve('a', '2.0.0', deps: {'c': '^1.0.0'}) + ..serve('a', '1.0.0') + ..serve('b', '2.0.0', deps: {'c': '^3.0.0'}) + ..serve('b', '1.0.0', deps: {'c': '^2.0.0'}) + ..serve('c', '3.0.0') + ..serve('c', '2.0.0') + ..serve('c', '1.0.0'); await d.appDir({'a': 'any', 'b': 'any'}).create(); await expectResolves(result: {'a': '1.0.0', 'b': '2.0.0', 'c': '3.0.0'}); @@ -716,20 +678,16 @@ // requirement only exists because of both a and b. The solver should be able // to deduce c 2.0.0's incompatibility and select c 1.0.0 instead. test('backjumps after a partial satisfier', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'x': '>=1.0.0'}); - builder.serve('b', '1.0.0', deps: {'x': '<2.0.0'}); - - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0', deps: {'a': 'any', 'b': 'any'}); - - builder.serve('x', '0.0.0'); - builder.serve('x', '1.0.0', deps: {'y': '1.0.0'}); - builder.serve('x', '2.0.0'); - - builder.serve('y', '1.0.0'); - builder.serve('y', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'x': '>=1.0.0'}) + ..serve('b', '1.0.0', deps: {'x': '<2.0.0'}) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0', deps: {'a': 'any', 'b': 'any'}) + ..serve('x', '0.0.0') + ..serve('x', '1.0.0', deps: {'y': '1.0.0'}) + ..serve('x', '2.0.0') + ..serve('y', '1.0.0') + ..serve('y', '2.0.0'); await d.appDir({'c': 'any', 'y': '^2.0.0'}).create(); await expectResolves(result: {'c': '1.0.0', 'y': '2.0.0'}, tries: 2); @@ -738,16 +696,15 @@ // This matches the Branching Error Reporting example in the version solver // documentation, and tests that we display line numbers correctly. test('branching error reporting', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'a': '^1.0.0', 'b': '^1.0.0'}); - builder.serve('foo', '1.1.0', deps: {'x': '^1.0.0', 'y': '^1.0.0'}); - builder.serve('a', '1.0.0', deps: {'b': '^2.0.0'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '2.0.0'); - builder.serve('x', '1.0.0', deps: {'y': '^2.0.0'}); - builder.serve('y', '1.0.0'); - builder.serve('y', '2.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'a': '^1.0.0', 'b': '^1.0.0'}) + ..serve('foo', '1.1.0', deps: {'x': '^1.0.0', 'y': '^1.0.0'}) + ..serve('a', '1.0.0', deps: {'b': '^2.0.0'}) + ..serve('b', '1.0.0') + ..serve('b', '2.0.0') + ..serve('x', '1.0.0', deps: {'y': '^2.0.0'}) + ..serve('y', '1.0.0') + ..serve('y', '2.0.0'); await d.appDir({'foo': '^1.0.0'}).create(); await expectResolves( @@ -772,14 +729,13 @@ // will resolve the problem. This test validates that b, which is farther // in the dependency graph from myapp is downgraded first. test('rolls back leaf versions first', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'b': 'any'}); - builder.serve('a', '2.0.0', deps: {'b': 'any', 'c': '2.0.0'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '2.0.0', deps: {'c': '1.0.0'}); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'b': 'any'}) + ..serve('a', '2.0.0', deps: {'b': 'any', 'c': '2.0.0'}) + ..serve('b', '1.0.0') + ..serve('b', '2.0.0', deps: {'c': '1.0.0'}) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0'); await d.appDir({'a': 'any'}).create(); await expectResolves(result: {'a': '2.0.0', 'b': '1.0.0', 'c': '2.0.0'}); @@ -788,15 +744,14 @@ // Only one version of baz, so foo and bar will have to downgrade until they // reach it. test('simple transitive', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '2.0.0', deps: {'bar': '2.0.0'}); - builder.serve('foo', '3.0.0', deps: {'bar': '3.0.0'}); - builder.serve('bar', '1.0.0', deps: {'baz': 'any'}); - builder.serve('bar', '2.0.0', deps: {'baz': '2.0.0'}); - builder.serve('bar', '3.0.0', deps: {'baz': '3.0.0'}); - builder.serve('baz', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '2.0.0', deps: {'bar': '2.0.0'}) + ..serve('foo', '3.0.0', deps: {'bar': '3.0.0'}) + ..serve('bar', '1.0.0', deps: {'baz': 'any'}) + ..serve('bar', '2.0.0', deps: {'baz': '2.0.0'}) + ..serve('bar', '3.0.0', deps: {'baz': '3.0.0'}) + ..serve('baz', '1.0.0'); await d.appDir({'foo': 'any'}).create(); await expectResolves( @@ -808,14 +763,13 @@ // make sure b has more versions than a so that the solver tries a first // since it sorts sibling dependencies by number of versions. test('backjump to nearer unsatisfied package', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'c': '1.0.0'}); - builder.serve('a', '2.0.0', deps: {'c': '2.0.0-nonexistent'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '2.0.0'); - builder.serve('b', '3.0.0'); - builder.serve('c', '1.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'c': '1.0.0'}) + ..serve('a', '2.0.0', deps: {'c': '2.0.0-nonexistent'}) + ..serve('b', '1.0.0') + ..serve('b', '2.0.0') + ..serve('b', '3.0.0') + ..serve('c', '1.0.0'); await d.appDir({'a': 'any', 'b': 'any'}).create(); await expectResolves( @@ -839,18 +793,17 @@ test('successful backjump to conflicting source', () async { await d.dir('a', [d.libPubspec('a', '1.0.0')]).create(); - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0', deps: {'a': 'any'}); - builder.serve('b', '2.0.0', deps: { + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0', deps: {'a': 'any'}) + ..serve('b', '2.0.0', deps: { 'a': {'path': p.join(d.sandbox, 'a')} - }); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - builder.serve('c', '3.0.0'); - builder.serve('c', '4.0.0'); - builder.serve('c', '5.0.0'); - }); + }) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0') + ..serve('c', '3.0.0') + ..serve('c', '4.0.0') + ..serve('c', '5.0.0'); await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create(); await expectResolves(result: {'a': '1.0.0', 'b': '1.0.0', 'c': '5.0.0'}); @@ -858,24 +811,22 @@ // Like the above test, but for a conflicting description. test('successful backjump to conflicting description', () async { - var otherServer = await PackageServer.start((builder) { - builder.serve('a', '1.0.0'); - }); + var otherServer = await startPackageServer(); + otherServer.serve('a', '1.0.0'); - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0', deps: {'a': 'any'}); - builder.serve('b', '2.0.0', deps: { + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0', deps: {'a': 'any'}) + ..serve('b', '2.0.0', deps: { 'a': { 'hosted': {'name': 'a', 'url': otherServer.url} } - }); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - builder.serve('c', '3.0.0'); - builder.serve('c', '4.0.0'); - builder.serve('c', '5.0.0'); - }); + }) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0') + ..serve('c', '3.0.0') + ..serve('c', '4.0.0') + ..serve('c', '5.0.0'); await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create(); await expectResolves(result: {'a': '1.0.0', 'b': '1.0.0', 'c': '5.0.0'}); @@ -886,17 +837,16 @@ test('failing backjump to conflicting source', () async { await d.dir('a', [d.libPubspec('a', '1.0.0')]).create(); - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0', deps: { + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0', deps: { 'a': {'path': p.join(d.sandbox, 'shared')} - }); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - builder.serve('c', '3.0.0'); - builder.serve('c', '4.0.0'); - builder.serve('c', '5.0.0'); - }); + }) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0') + ..serve('c', '3.0.0') + ..serve('c', '4.0.0') + ..serve('c', '5.0.0'); await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -907,23 +857,21 @@ }); test('failing backjump to conflicting description', () async { - var otherServer = await PackageServer.start((builder) { - builder.serve('a', '1.0.0'); - }); + var otherServer = await startPackageServer(); + otherServer.serve('a', '1.0.0'); - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0', deps: { + await servePackages() + ..serve('a', '1.0.0') + ..serve('b', '1.0.0', deps: { 'a': { 'hosted': {'name': 'a', 'url': otherServer.url} } - }); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - builder.serve('c', '3.0.0'); - builder.serve('c', '4.0.0'); - builder.serve('c', '5.0.0'); - }); + }) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0') + ..serve('c', '3.0.0') + ..serve('c', '4.0.0') + ..serve('c', '5.0.0'); await d.appDir({'a': 'any', 'b': 'any', 'c': 'any'}).create(); await expectResolves( @@ -942,39 +890,37 @@ // Since b has fewer versions, it will be traversed first, which means a will // come later. Since later selections are revised first, a gets downgraded. test('traverse into package with fewer versions first', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'c': 'any'}); - builder.serve('a', '2.0.0', deps: {'c': 'any'}); - builder.serve('a', '3.0.0', deps: {'c': 'any'}); - builder.serve('a', '4.0.0', deps: {'c': 'any'}); - builder.serve('a', '5.0.0', deps: {'c': '1.0.0'}); - builder.serve('b', '1.0.0', deps: {'c': 'any'}); - builder.serve('b', '2.0.0', deps: {'c': 'any'}); - builder.serve('b', '3.0.0', deps: {'c': 'any'}); - builder.serve('b', '4.0.0', deps: {'c': '2.0.0'}); - builder.serve('c', '1.0.0'); - builder.serve('c', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'c': 'any'}) + ..serve('a', '2.0.0', deps: {'c': 'any'}) + ..serve('a', '3.0.0', deps: {'c': 'any'}) + ..serve('a', '4.0.0', deps: {'c': 'any'}) + ..serve('a', '5.0.0', deps: {'c': '1.0.0'}) + ..serve('b', '1.0.0', deps: {'c': 'any'}) + ..serve('b', '2.0.0', deps: {'c': 'any'}) + ..serve('b', '3.0.0', deps: {'c': 'any'}) + ..serve('b', '4.0.0', deps: {'c': '2.0.0'}) + ..serve('c', '1.0.0') + ..serve('c', '2.0.0'); await d.appDir({'a': 'any', 'b': 'any'}).create(); await expectResolves(result: {'a': '4.0.0', 'b': '4.0.0', 'c': '2.0.0'}); }); test('complex backtrack', () async { - await servePackages((builder) { - // This sets up a hundred versions of foo and bar, 0.0.0 through 9.9.0. Each - // version of foo depends on a baz with the same major version. Each version - // of bar depends on a baz with the same minor version. There is only one - // version of baz, 0.0.0, so only older versions of foo and bar will - // satisfy it. - builder.serve('baz', '0.0.0'); - for (var i = 0; i < 10; i++) { - for (var j = 0; j < 10; j++) { - builder.serve('foo', '$i.$j.0', deps: {'baz': '$i.0.0'}); - builder.serve('bar', '$i.$j.0', deps: {'baz': '0.$j.0'}); - } + final server = await servePackages(); + // This sets up a hundred versions of foo and bar, 0.0.0 through 9.9.0. Each + // version of foo depends on a baz with the same major version. Each version + // of bar depends on a baz with the same minor version. There is only one + // version of baz, 0.0.0, so only older versions of foo and bar will + // satisfy it. + server.serve('baz', '0.0.0'); + for (var i = 0; i < 10; i++) { + for (var j = 0; j < 10; j++) { + server.serve('foo', '$i.$j.0', deps: {'baz': '$i.0.0'}); + server.serve('bar', '$i.$j.0', deps: {'baz': '0.$j.0'}); } - }); + } await d.appDir({'foo': 'any', 'bar': 'any'}).create(); await expectResolves( @@ -985,19 +931,18 @@ // versions of it is a waste of time: no possible versions can match. We need // to jump past it to the most recent package that affected the constraint. test('backjump past failed package on disjoint constraint', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: { + await servePackages() + ..serve('a', '1.0.0', deps: { 'foo': 'any' // ok - }); - builder.serve('a', '2.0.0', deps: { + }) + ..serve('a', '2.0.0', deps: { 'foo': '<1.0.0' // disjoint with myapp's constraint on foo - }); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '2.0.1'); - builder.serve('foo', '2.0.2'); - builder.serve('foo', '2.0.3'); - builder.serve('foo', '2.0.4'); - }); + }) + ..serve('foo', '2.0.0') + ..serve('foo', '2.0.1') + ..serve('foo', '2.0.2') + ..serve('foo', '2.0.3') + ..serve('foo', '2.0.4'); await d.appDir({'a': 'any', 'foo': '>2.0.0'}).create(); await expectResolves(result: {'a': '1.0.0', 'foo': '2.0.4'}); @@ -1008,14 +953,13 @@ // would backtrack over the failed package instead of trying different // versions of it. test('finds solution with less strict constraint', () async { - await servePackages((builder) { - builder.serve('a', '2.0.0'); - builder.serve('a', '1.0.0'); - builder.serve('b', '1.0.0', deps: {'a': '1.0.0'}); - builder.serve('c', '1.0.0', deps: {'b': 'any'}); - builder.serve('d', '2.0.0', deps: {'myapp': 'any'}); - builder.serve('d', '1.0.0', deps: {'myapp': '<1.0.0'}); - }); + await servePackages() + ..serve('a', '2.0.0') + ..serve('a', '1.0.0') + ..serve('b', '1.0.0', deps: {'a': '1.0.0'}) + ..serve('c', '1.0.0', deps: {'b': 'any'}) + ..serve('d', '2.0.0', deps: {'myapp': 'any'}) + ..serve('d', '1.0.0', deps: {'myapp': '<1.0.0'}); await d.appDir({'a': 'any', 'c': 'any', 'd': 'any'}).create(); await expectResolves( @@ -1051,10 +995,9 @@ }); test('dependency does not match SDK', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'environment': {'sdk': '0.0.0'} - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'environment': {'sdk': '0.0.0'} }); await d.appDir({'foo': 'any'}).create(); @@ -1067,12 +1010,11 @@ }); test('transitive dependency does not match SDK', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('bar', '1.0.0', pubspec: { 'environment': {'sdk': '0.0.0'} }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(error: equalsIgnoringWhitespace(''' @@ -1085,41 +1027,39 @@ }); test('selects a dependency version that allows the SDK', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('foo', '2.0.0', pubspec: { + }) + ..serve('foo', '2.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('foo', '3.0.0', pubspec: { + }) + ..serve('foo', '3.0.0', pubspec: { + 'environment': {'sdk': '0.0.0'} + }) + ..serve('foo', '4.0.0', pubspec: { 'environment': {'sdk': '0.0.0'} }); - builder.serve('foo', '4.0.0', pubspec: { - 'environment': {'sdk': '0.0.0'} - }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '2.0.0'}); }); test('selects a transitive dependency version that allows the SDK', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': 'any'}); - builder.serve('bar', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': 'any'}) + ..serve('bar', '1.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('bar', '2.0.0', pubspec: { + }) + ..serve('bar', '2.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('bar', '3.0.0', pubspec: { + }) + ..serve('bar', '3.0.0', pubspec: { + 'environment': {'sdk': '0.0.0'} + }) + ..serve('bar', '4.0.0', pubspec: { 'environment': {'sdk': '0.0.0'} }); - builder.serve('bar', '4.0.0', pubspec: { - 'environment': {'sdk': '0.0.0'} - }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '2.0.0'}); @@ -1128,24 +1068,23 @@ test( 'selects a dependency version that allows a transitive ' 'dependency that allows the SDK', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '2.0.0', deps: {'bar': '2.0.0'}); - builder.serve('foo', '3.0.0', deps: {'bar': '3.0.0'}); - builder.serve('foo', '4.0.0', deps: {'bar': '4.0.0'}); - builder.serve('bar', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '2.0.0', deps: {'bar': '2.0.0'}) + ..serve('foo', '3.0.0', deps: {'bar': '3.0.0'}) + ..serve('foo', '4.0.0', deps: {'bar': '4.0.0'}) + ..serve('bar', '1.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('bar', '2.0.0', pubspec: { + }) + ..serve('bar', '2.0.0', pubspec: { 'environment': {'sdk': '0.1.2+3'} - }); - builder.serve('bar', '3.0.0', pubspec: { + }) + ..serve('bar', '3.0.0', pubspec: { + 'environment': {'sdk': '0.0.0'} + }) + ..serve('bar', '4.0.0', pubspec: { 'environment': {'sdk': '0.0.0'} }); - builder.serve('bar', '4.0.0', pubspec: { - 'environment': {'sdk': '0.0.0'} - }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '2.0.0', 'bar': '2.0.0'}, tries: 2); @@ -1463,10 +1402,9 @@ }); test('fails for a dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'environment': {'flutter': '0.0.0'} - }); + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'environment': {'flutter': '0.0.0'} }); await d.appDir({'foo': 'any'}).create(); @@ -1479,13 +1417,12 @@ }); test("chooses a version that doesn't need Flutter", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '3.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0') + ..serve('foo', '3.0.0', pubspec: { 'environment': {'flutter': '0.0.0'} }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves(result: {'foo': '2.0.0'}); @@ -1612,17 +1549,16 @@ }); test('selects the latest dependency with a matching constraint', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'environment': {'flutter': '^0.0.0'} - }); - builder.serve('foo', '2.0.0', pubspec: { + }) + ..serve('foo', '2.0.0', pubspec: { 'environment': {'flutter': '^1.0.0'} - }); - builder.serve('foo', '3.0.0', pubspec: { + }) + ..serve('foo', '3.0.0', pubspec: { 'environment': {'flutter': '^2.0.0'} }); - }); await d.appDir({'foo': 'any'}).create(); await expectResolves( @@ -1634,36 +1570,33 @@ void prerelease() { test('prefer stable versions over unstable', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '1.1.0-dev'); - builder.serve('a', '2.0.0-dev'); - builder.serve('a', '3.0.0-dev'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '1.1.0-dev') + ..serve('a', '2.0.0-dev') + ..serve('a', '3.0.0-dev'); await d.appDir({'a': 'any'}).create(); await expectResolves(result: {'a': '1.0.0'}); }); test('use latest allowed prerelease if no stable versions match', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0-dev'); - builder.serve('a', '1.1.0-dev'); - builder.serve('a', '1.9.0-dev'); - builder.serve('a', '3.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0-dev') + ..serve('a', '1.1.0-dev') + ..serve('a', '1.9.0-dev') + ..serve('a', '3.0.0'); await d.appDir({'a': '<2.0.0'}).create(); await expectResolves(result: {'a': '1.9.0-dev'}); }); test('use an earlier stable version on a < constraint', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '1.1.0'); - builder.serve('a', '2.0.0-dev'); - builder.serve('a', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '1.1.0') + ..serve('a', '2.0.0-dev') + ..serve('a', '2.0.0'); await d.appDir({'a': '<2.0.0'}).create(); await expectResolves(result: {'a': '1.1.0'}); @@ -1671,33 +1604,30 @@ test('prefer a stable version even if constraint mentions unstable', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '1.1.0'); - builder.serve('a', '2.0.0-dev'); - builder.serve('a', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '1.1.0') + ..serve('a', '2.0.0-dev') + ..serve('a', '2.0.0'); await d.appDir({'a': '<=2.0.0-dev'}).create(); await expectResolves(result: {'a': '1.1.0'}); }); test('use pre-release when desired', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '1.1.0-dev'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '1.1.0-dev'); await d.appDir({'a': '^1.1.0-dev'}).create(); await expectResolves(result: {'a': '1.1.0-dev'}); }); test('can upgrade from pre-release', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '1.1.0-dev'); - builder.serve('a', '1.1.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '1.1.0-dev') + ..serve('a', '1.1.0'); await d.appDir({'a': '^1.1.0-dev'}).create(); await expectResolves(result: {'a': '1.1.0'}); @@ -1706,12 +1636,11 @@ test('will use pre-release if depended on in stable release', () async { // This behavior is desired because a stable package has dependency on a // pre-release. - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'}); - builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '1.1.0-dev'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'b': '^1.0.0'}) + ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}) + ..serve('b', '1.0.0') + ..serve('b', '1.1.0-dev'); await d.appDir({'a': '^1.0.0'}).create(); await expectResolves(result: { @@ -1721,12 +1650,11 @@ }); test('backtracks pre-release choice with direct dependency', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'}); - builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '1.1.0-dev'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'b': '^1.0.0'}) + ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}) + ..serve('b', '1.0.0') + ..serve('b', '1.1.0-dev'); await d.appDir({ 'a': '^1.0.0', @@ -1741,13 +1669,12 @@ test('backtracking pre-release fails with indirect dependency', () async { // NOTE: This behavior is not necessarily desired. // If feasible it might worth changing this behavior in the future. - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'b': '^1.0.0'}); - builder.serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}); - builder.serve('b', '1.0.0'); - builder.serve('b', '1.1.0-dev'); - builder.serve('c', '1.0.0', deps: {'b': '^1.0.0'}); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'b': '^1.0.0'}) + ..serve('a', '1.1.0', deps: {'b': '^1.1.0-dev'}) + ..serve('b', '1.0.0') + ..serve('b', '1.1.0-dev') + ..serve('c', '1.0.0', deps: {'b': '^1.0.0'}); await d.appDir({ 'a': '^1.0.0', @@ -1762,14 +1689,13 @@ test('https://github.com/dart-lang/pub/issues/3057 regression', () async { // This used to cause an infinite loop. - await servePackages((builder) { - builder.serve('a', '0.12.0', deps: {}); - builder.serve('b', '0.1.0', deps: {'c': '2.0.0'}); - builder.serve('b', '0.9.0-1', deps: {'c': '^1.6.0'}); - builder.serve('b', '0.10.0', deps: {'a': '1.0.0'}); - builder.serve('b', '0.17.0', deps: {'a': '1.0.0'}); - builder.serve('c', '2.0.1', deps: {}); - }); + await servePackages() + ..serve('a', '0.12.0', deps: {}) + ..serve('b', '0.1.0', deps: {'c': '2.0.0'}) + ..serve('b', '0.9.0-1', deps: {'c': '^1.6.0'}) + ..serve('b', '0.10.0', deps: {'a': '1.0.0'}) + ..serve('b', '0.17.0', deps: {'a': '1.0.0'}) + ..serve('c', '2.0.1', deps: {}); await d.appDir( { @@ -1784,13 +1710,12 @@ }); test('https://github.com/dart-lang/pub/pull/3038 regression', () async { - await servePackages((builder) { - builder.serve('a', '1.1.0', deps: {'b': '^1.0.0'}); - builder.serve('b', '1.0.0', deps: {'c': '^1.0.0'}); - builder.serve('c', '0.9.0'); - builder.serve('b', '1.1.0-alpha'); - builder.serve('a', '1.0.0', deps: {'b': '^1.1.0-alpha'}); - }); + await servePackages() + ..serve('a', '1.1.0', deps: {'b': '^1.0.0'}) + ..serve('b', '1.0.0', deps: {'c': '^1.0.0'}) + ..serve('c', '0.9.0') + ..serve('b', '1.1.0-alpha') + ..serve('a', '1.0.0', deps: {'b': '^1.1.0-alpha'}); await d.appDir({ 'a': '^1.0.0', @@ -1801,11 +1726,10 @@ void override() { test('chooses best version matching override constraint', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '2.0.0'); - builder.serve('a', '3.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '2.0.0') + ..serve('a', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -1819,11 +1743,10 @@ }); test('uses override as dependency', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '2.0.0'); - builder.serve('a', '3.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '2.0.0') + ..serve('a', '3.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -1836,13 +1759,12 @@ }); test('ignores other constraints on overridden package', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '2.0.0'); - builder.serve('a', '3.0.0'); - builder.serve('b', '1.0.0', deps: {'a': '1.0.0'}); - builder.serve('c', '1.0.0', deps: {'a': '3.0.0'}); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '2.0.0') + ..serve('a', '3.0.0') + ..serve('b', '1.0.0', deps: {'a': '1.0.0'}) + ..serve('c', '1.0.0', deps: {'a': '3.0.0'}); await d.dir(appPath, [ d.pubspec({ @@ -1856,12 +1778,11 @@ }); test('backtracks on overidden package for its constraints', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0', deps: {'shared': 'any'}); - builder.serve('a', '2.0.0', deps: {'shared': '1.0.0'}); - builder.serve('shared', '1.0.0'); - builder.serve('shared', '2.0.0'); - }); + await servePackages() + ..serve('a', '1.0.0', deps: {'shared': 'any'}) + ..serve('a', '2.0.0', deps: {'shared': '1.0.0'}) + ..serve('shared', '1.0.0') + ..serve('shared', '2.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -1875,14 +1796,13 @@ }); test('override compatible with locked dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'}); - builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.0.1'); - builder.serve('bar', '1.0.2'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'}) + ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'}) + ..serve('bar', '1.0.0') + ..serve('bar', '1.0.1') + ..serve('bar', '1.0.2'); await d.appDir({'foo': '1.0.1'}).create(); await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'}); @@ -1898,14 +1818,13 @@ }); test('override incompatible with locked dependency', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'bar': '1.0.0'}); - builder.serve('foo', '1.0.1', deps: {'bar': '1.0.1'}); - builder.serve('foo', '1.0.2', deps: {'bar': '1.0.2'}); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '1.0.1'); - builder.serve('bar', '1.0.2'); - }); + await servePackages() + ..serve('foo', '1.0.0', deps: {'bar': '1.0.0'}) + ..serve('foo', '1.0.1', deps: {'bar': '1.0.1'}) + ..serve('foo', '1.0.2', deps: {'bar': '1.0.2'}) + ..serve('bar', '1.0.0') + ..serve('bar', '1.0.1') + ..serve('bar', '1.0.2'); await d.appDir({'foo': '1.0.1'}).create(); await expectResolves(result: {'foo': '1.0.1', 'bar': '1.0.1'}); @@ -1921,10 +1840,9 @@ }); test('no version that matches override', () async { - await servePackages((builder) { - builder.serve('foo', '2.0.0'); - builder.serve('foo', '2.1.3'); - }); + await servePackages() + ..serve('foo', '2.0.0') + ..serve('foo', '2.1.3'); await d.dir(appPath, [ d.pubspec({ @@ -1940,9 +1858,8 @@ }); test('overrides a bad source without error', () async { - await servePackages((builder) { - builder.serve('foo', '0.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '0.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -1958,10 +1875,9 @@ }); test('overrides an unmatched SDK constraint', () async { - await servePackages((builder) { - builder.serve('foo', '0.0.0', pubspec: { - 'environment': {'sdk': '0.0.0'} - }); + final server = await servePackages(); + server.serve('foo', '0.0.0', pubspec: { + 'environment': {'sdk': '0.0.0'} }); await d.dir(appPath, [ @@ -1975,9 +1891,8 @@ }); test('overrides an unmatched root dependency', () async { - await servePackages((builder) { - builder.serve('foo', '0.0.0', deps: {'myapp': '1.0.0'}); - }); + final server = await servePackages(); + server.serve('foo', '0.0.0', deps: {'myapp': '1.0.0'}); await d.dir(appPath, [ d.pubspec({ @@ -1992,11 +1907,10 @@ // Regression test for #1853 test("overrides a locked package's dependency", () async { - await servePackages((builder) { - builder.serve('foo', '1.2.3', deps: {'bar': '1.2.3'}); - builder.serve('bar', '1.2.3'); - builder.serve('bar', '0.0.1'); - }); + await servePackages() + ..serve('foo', '1.2.3', deps: {'bar': '1.2.3'}) + ..serve('bar', '1.2.3') + ..serve('bar', '0.0.1'); await d.appDir({'foo': 'any'}).create(); @@ -2016,12 +1930,11 @@ void downgrade() { test('downgrades a dependency to the lowest matching version', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '2.0.0-dev'); - builder.serve('foo', '2.0.0'); - builder.serve('foo', '2.1.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '2.0.0-dev') + ..serve('foo', '2.0.0') + ..serve('foo', '2.1.0'); await d.appDir({'foo': '2.1.0'}).create(); await expectResolves(result: {'foo': '2.1.0'}); @@ -2033,12 +1946,11 @@ test( 'use earliest allowed prerelease if no stable versions match ' 'while downgrading', () async { - await servePackages((builder) { - builder.serve('a', '1.0.0'); - builder.serve('a', '2.0.0-dev.1'); - builder.serve('a', '2.0.0-dev.2'); - builder.serve('a', '2.0.0-dev.3'); - }); + await servePackages() + ..serve('a', '1.0.0') + ..serve('a', '2.0.0-dev.1') + ..serve('a', '2.0.0-dev.2') + ..serve('a', '2.0.0-dev.3'); await d.appDir({'a': '>=2.0.0-dev.1 <3.0.0'}).create(); await expectResolves(result: {'a': '2.0.0-dev.1'}, downgrade: true); @@ -2047,67 +1959,63 @@ void features() { test("doesn't enable an opt-in feature by default", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0'}); }); test('enables an opt-out feature by default', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': true, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}); }); test('features are opt-out by default', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves(result: {'foo': '1.0.0', 'bar': '1.0.0'}); }); test("enables an opt-in feature if it's required", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2119,16 +2027,15 @@ }); test("doesn't enable an opt-out feature if it's disabled", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2140,22 +2047,21 @@ }); test('opting in takes precedence over opting out', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0', deps: { + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0', deps: { 'foo': { 'version': '1.0.0', 'features': {'stuff': true} } }); - }); await d.appDir({ 'foo': { @@ -2169,21 +2075,20 @@ }); test('implicitly opting in takes precedence over opting out', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0', deps: { + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0', deps: { 'foo': { 'version': '1.0.0', } }); - }); await d.appDir({ 'foo': { @@ -2197,18 +2102,17 @@ }); test("doesn't select a version with an unavailable feature", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('foo', '1.1.0'); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('foo', '1.1.0') + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2220,26 +2124,25 @@ }); test("doesn't select a version with an incompatible feature", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('foo', '1.1.0', pubspec: { + }) + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '2.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - builder.serve('bar', '2.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('bar', '2.0.0'); await d.appDir({ 'foo': { @@ -2254,8 +2157,8 @@ test( 'backtracks if a feature is transitively incompatible with another ' 'feature', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, @@ -2267,27 +2170,24 @@ } } } - }); - builder.serve('foo', '1.1.0', pubspec: { + }) + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - - builder.serve('bar', '1.0.0', pubspec: { + }) + ..serve('bar', '1.0.0', pubspec: { 'features': { 'stuff': { 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('baz', '1.0.0'); - builder.serve('baz', '2.0.0'); - }); + }) + ..serve('baz', '1.0.0') + ..serve('baz', '2.0.0'); await d.appDir({ 'foo': { @@ -2302,30 +2202,27 @@ test("backtracks if a feature's dependencies are transitively incompatible", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('foo', '1.1.0', pubspec: { + }) + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '2.0.0'} } } - }); - - builder.serve('bar', '1.0.0', deps: {'baz': '1.0.0'}); - builder.serve('bar', '2.0.0', deps: {'baz': '2.0.0'}); - - builder.serve('baz', '1.0.0'); - builder.serve('baz', '2.0.0'); - }); + }) + ..serve('bar', '1.0.0', deps: {'baz': '1.0.0'}) + ..serve('bar', '2.0.0', deps: {'baz': '2.0.0'}) + ..serve('baz', '1.0.0') + ..serve('baz', '2.0.0'); await d.appDir({ 'foo': { @@ -2339,9 +2236,9 @@ }); test('disables a feature when it backtracks', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: {'myapp': '0.0.0'}); - builder.serve('foo', '1.1.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: {'myapp': '0.0.0'}) + ..serve('foo', '1.1.0', deps: { // This is a transitively incompatible dependency with myapp, which will // force the solver to backtrack and unselect foo 1.1.0. 'bar': '1.0.0', @@ -2349,15 +2246,11 @@ 'version': '0.0.0', 'features': {'stuff': true} } - }); - - builder.serve('bar', '1.0.0', deps: {'baz': '2.0.0'}); - - builder.serve('baz', '1.0.0'); - builder.serve('baz', '2.0.0'); - - builder.serve('qux', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0', deps: {'baz': '2.0.0'}) + ..serve('baz', '1.0.0') + ..serve('baz', '2.0.0') + ..serve('qux', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2375,10 +2268,9 @@ }); test("the root package's features are opt-out by default", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2395,10 +2287,9 @@ }); test("the root package's features can be made opt-in", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('bar', '1.0.0'); - }); + await servePackages() + ..serve('foo', '1.0.0') + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2421,14 +2312,13 @@ // increases the total number of dependencies. test("the root package's features can't be disabled by dependencies", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: { 'myapp': { 'features': {'stuff': false} } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2445,14 +2335,13 @@ }); test("the root package's features can be enabled by dependencies", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', deps: { + await servePackages() + ..serve('foo', '1.0.0', deps: { 'myapp': { 'features': {'stuff': true} } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2470,9 +2359,8 @@ }); test("resolution fails because a feature doesn't exist", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.dir(appPath, [ d.pubspec({ @@ -2492,17 +2380,16 @@ group('an "if available" dependency', () { test('enables an opt-in feature', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2514,9 +2401,8 @@ }); test("is compatible with a feature that doesn't exist", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - }); + final server = await servePackages(); + server.serve('foo', '1.0.0'); await d.appDir({ 'foo': { @@ -2535,14 +2421,13 @@ group('succeeds when', () { test('a Dart SDK constraint is matched', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'features': { - 'stuff': { - 'environment': {'sdk': '^0.1.0'} - } + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'features': { + 'stuff': { + 'environment': {'sdk': '^0.1.0'} } - }); + } }); await d.dir(appPath, [ @@ -2556,14 +2441,13 @@ }); test('a Flutter SDK constraint is matched', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'features': { - 'stuff': { - 'environment': {'flutter': '^1.0.0'} - } + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'features': { + 'stuff': { + 'environment': {'flutter': '^1.0.0'} } - }); + } }); await d.dir(appPath, [ @@ -2581,16 +2465,15 @@ group("doesn't choose a version because", () { test("a Dart SDK constraint isn't matched", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.1.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'environment': {'sdk': '0.0.1'} } } }); - }); await d.dir(appPath, [ d.pubspec({ @@ -2603,16 +2486,15 @@ }); test("Flutter isn't available", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.1.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'environment': {'flutter': '1.0.0'} } } }); - }); await d.dir(appPath, [ d.pubspec({ @@ -2625,16 +2507,15 @@ }); test("a Flutter SDK constraint isn't matched", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0'); - builder.serve('foo', '1.1.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0') + ..serve('foo', '1.1.0', pubspec: { 'features': { 'stuff': { 'environment': {'flutter': '^2.0.0'} } } }); - }); await d.dir(appPath, [ d.pubspec({ @@ -2651,14 +2532,13 @@ group('resolution fails because', () { test("a Dart SDK constraint isn't matched", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'features': { - 'stuff': { - 'environment': {'sdk': '0.0.1'} - } + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'features': { + 'stuff': { + 'environment': {'sdk': '0.0.1'} } - }); + } }); await d.dir(appPath, [ @@ -2675,14 +2555,13 @@ }); test("Flutter isn't available", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'features': { - 'stuff': { - 'environment': {'flutter': '1.0.0'} - } + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'features': { + 'stuff': { + 'environment': {'flutter': '1.0.0'} } - }); + } }); await d.dir(appPath, [ @@ -2698,14 +2577,13 @@ }); test("a Flutter SDK constraint isn't matched", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { - 'features': { - 'stuff': { - 'environment': {'flutter': '^2.0.0'} - } + final server = await servePackages(); + server.serve('foo', '1.0.0', pubspec: { + 'features': { + 'stuff': { + 'environment': {'flutter': '^2.0.0'} } - }); + } }); await d.dir(appPath, [ @@ -2725,8 +2603,8 @@ group('with overlapping dependencies', () { test('can enable extra features', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'dependencies': {'bar': '1.0.0'}, 'features': { 'stuff': { @@ -2738,19 +2616,16 @@ } } } - }); - - builder.serve('bar', '1.0.0', pubspec: { + }) + ..serve('bar', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': false, 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('baz', '1.0.0'); await d.appDir({ 'foo': {'version': '1.0.0'} @@ -2768,8 +2643,8 @@ }); test("can't disable features", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'dependencies': { 'bar': { 'version': '1.0.0', @@ -2786,19 +2661,16 @@ } } } - }); - - builder.serve('bar', '1.0.0', pubspec: { + }) + ..serve('bar', '1.0.0', pubspec: { 'features': { 'stuff': { 'default': true, 'dependencies': {'baz': '1.0.0'} } } - }); - - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('baz', '1.0.0'); await d.appDir({ 'foo': { @@ -2813,8 +2685,8 @@ group('with required features', () { test('enables those features', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'main': { 'default': false, @@ -2829,10 +2701,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await d.appDir({ 'foo': { @@ -2845,8 +2716,8 @@ }); test('enables those features by default', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'main': { 'requires': ['required1', 'required2'] @@ -2860,10 +2731,9 @@ 'dependencies': {'baz': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - builder.serve('baz', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0') + ..serve('baz', '1.0.0'); await d.appDir({'foo': '1.0.0'}).create(); await expectResolves( @@ -2871,8 +2741,8 @@ }); test("doesn't enable those features if it's disabled", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'main': { 'requires': ['required'] @@ -2882,9 +2752,8 @@ 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2897,8 +2766,8 @@ test("enables those features even if they'd otherwise be disabled", () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'main': { 'requires': ['required'] @@ -2908,9 +2777,8 @@ 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2922,8 +2790,8 @@ }); test('enables features transitively', () async { - await servePackages((builder) { - builder.serve('foo', '1.0.0', pubspec: { + await servePackages() + ..serve('foo', '1.0.0', pubspec: { 'features': { 'main': { 'requires': ['required1'] @@ -2937,9 +2805,8 @@ 'dependencies': {'bar': '1.0.0'} } } - }); - builder.serve('bar', '1.0.0'); - }); + }) + ..serve('bar', '1.0.0'); await d.appDir({ 'foo': { @@ -2972,11 +2839,11 @@ /// /// If [downgrade] is `true`, this runs "pub downgrade" instead of "pub get". Future expectResolves( - {Map result, + {Map? result, error, output, - int tries, - Map<String, String> environment, + int? tries, + Map<String, String>? environment, bool downgrade = false}) async { await runPub( args: [downgrade ? 'downgrade' : 'get'], @@ -3001,12 +2868,13 @@ for (var dep in resultPubspec.dependencies.values) { expect(ids, contains(dep.name)); var id = ids.remove(dep.name); + final source = dep.source; - if (dep.source is HostedSource && dep.description is String) { + if (source is HostedSource && (dep.description.uri == source.defaultUrl)) { // If the dep uses the default hosted source, grab it from the test // package server rather than pub.dartlang.org. dep = registry.hosted - .refFor(dep.name, url: Uri.parse(globalPackageServer.url)) + .refFor(dep.name, url: Uri.parse(globalServer.url)) .withConstraint(dep.constraint); } expect(dep.allows(id), isTrue, reason: 'Expected $id to match $dep.'); @@ -3014,3 +2882,20 @@ expect(ids, isEmpty, reason: 'Expected no additional packages.'); } + +void regressions() { + test('reformatRanges with a build', () async { + await servePackages() + ..serve('integration_test', '1.0.1', + deps: {'vm_service': '>= 4.2.0 <6.0.0'}) + ..serve('integration_test', '1.0.2+2', + deps: {'vm_service': '>= 4.2.0 <7.0.0'}) + ..serve('vm_service', '7.3.0'); + await d.appDir({'integration_test': '^1.0.2'}).create(); + await expectResolves( + error: contains( + 'Because no versions of integration_test match >=1.0.2 <1.0.2+2', + ), + ); + }); +}
diff --git a/tool/extract_all_pub_dev.dart b/tool/extract_all_pub_dev.dart index 8d7f049..f96dc5a 100644 --- a/tool/extract_all_pub_dev.dart +++ b/tool/extract_all_pub_dev.dart
@@ -2,8 +2,6 @@ // 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. -// @dart=2.10 - /// This is a manual test that can be run to test the .tar.gz decoding. /// It will save progress in [statusFileName] such that it doesn't have to be /// finished in a single run. @@ -33,7 +31,7 @@ Future<void> main() async { var alreadyDonePackages = <String>{}; - var failures = <Map<String, dynamic>>[]; + var failures = <Map<String, dynamic>?>[]; if (fileExists(statusFilename)) { final json = jsonDecode(readTextFile(statusFilename)); for (final packageName in json['packages'] ?? []) {
diff --git a/tool/test-bin/pub_command_runner.dart b/tool/test-bin/pub_command_runner.dart index 2470a91..e438aae 100644 --- a/tool/test-bin/pub_command_runner.dart +++ b/tool/test-bin/pub_command_runner.dart
@@ -1,22 +1,50 @@ -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// @dart=2.10 - +/// A trivial embedding of the pub command. Used from tests. +import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; import 'package:args/command_runner.dart'; +import 'package:pub/pub.dart'; +import 'package:pub/src/command.dart'; import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:pub/src/log.dart' as log; -import 'package:pub/src/pub_embeddable_command.dart'; +import 'package:usage/usage.dart'; + +final _LoggingAnalytics loggingAnalytics = _LoggingAnalytics(); + +// A command for explicitly throwing an exception, to test the handling of +// unexpected eceptions. +class ThrowingCommand extends PubCommand { + @override + String get name => 'fail'; + + @override + String get description => 'Throws an exception'; + + bool get hide => true; + + @override + Future<int> runProtected() async { + throw StateError('Pub has crashed'); + } +} class Runner extends CommandRunner<int> { - ArgResults _options; + late ArgResults _options; Runner() : super('pub_command_runner', 'Tests the embeddable pub command.') { - addCommand(PubEmbeddableCommand()); + final analytics = Platform.environment['_PUB_LOG_ANALYTICS'] == 'true' + ? PubAnalytics(() => loggingAnalytics, + dependencyKindCustomDimensionName: 'cd1') + : null; + addCommand( + pubCommand(analytics: analytics, isVerbose: () => _options['verbose']) + ..addSubcommand(ThrowingCommand())); + argParser.addFlag('verbose'); } @override @@ -40,3 +68,51 @@ Future<void> main(List<String> arguments) async { exitCode = await Runner().run(arguments); } + +class _LoggingAnalytics extends AnalyticsMock { + _LoggingAnalytics() { + onSend.listen((event) { + stderr.writeln('[analytics]${json.encode(event)}'); + }); + } + + @override + bool get firstRun => false; + + @override + Future sendScreenView(String viewName, {Map<String, String>? parameters}) { + parameters ??= <String, String>{}; + parameters['viewName'] = viewName; + return _log('screenView', parameters); + } + + @override + Future sendEvent(String category, String action, + {String? label, int? value, Map<String, String>? parameters}) { + parameters ??= <String, String>{}; + return _log( + 'event', + {'category': category, 'action': action, 'label': label, 'value': value} + ..addAll(parameters)); + } + + @override + Future sendSocial(String network, String action, String target) => + _log('social', {'network': network, 'action': action, 'target': target}); + + @override + Future sendTiming(String variableName, int time, + {String? category, String? label}) { + return _log('timing', { + 'variableName': variableName, + 'time': time, + 'category': category, + 'label': label + }); + } + + Future<void> _log(String hitType, Map message) async { + final encoded = json.encode({'hitType': hitType, 'message': message}); + stderr.writeln('[analytics]: $encoded'); + } +}
diff --git a/tool/test.dart b/tool/test.dart index 2f4769d..7d98156 100755 --- a/tool/test.dart +++ b/tool/test.dart
@@ -3,8 +3,6 @@ // 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. -// @dart=2.10 - /// Test wrapper script. /// Many of the integration tests runs the `pub` command, this is slow if every /// invocation requires the dart compiler to load all the sources. This script @@ -19,7 +17,7 @@ import 'package:pub/src/exceptions.dart'; Future<void> main(List<String> args) async { - Process testProcess; + Process? testProcess; final sub = ProcessSignal.sigint.watch().listen((signal) { testProcess?.kill(signal); }); @@ -31,7 +29,7 @@ await precompile( executablePath: path.join('bin', 'pub.dart'), outputPath: pubSnapshotFilename, - incrementalDillOutputPath: pubSnapshotIncrementalFilename, + incrementalDillPath: pubSnapshotIncrementalFilename, name: 'bin/pub.dart', packageConfigPath: path.join('.dart_tool', 'package_config.json')); testProcess = await Process.start(