Skip to content

Merge dependency services #3303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d77c14e
Gitignore validator should not follow symlink dirs (#3209)
sigurdm Nov 5, 2021
efd24e6
Fix hanging event handler for `stdin`. (#3218)
jonasfj Nov 9, 2021
96404e0
Fix hanging event handler for `stdin`. (#3218)
jonasfj Nov 9, 2021
ff94188
Merge branch 'cherry-pick-for-2.15.0'
jonasfj Nov 9, 2021
a4d44c7
Global package server null safety (#3225)
jonasfj Nov 10, 2021
c888b01
Remove pedantic and cleanup a few lints (#3224)
jonasfj Nov 10, 2021
eaf3651
More links in the repository specification (#3220)
jonasfj Nov 11, 2021
1e78c68
Better error messages round 2 (#3223)
jonasfj Nov 11, 2021
acc8ab0
Refactor the test package-server (#3230)
sigurdm Nov 16, 2021
dc85752
Remove duplicated lines in testdata (#3234)
sigurdm Nov 18, 2021
b9edfa5
Support publishing to a hosted-url with a /path
jonasfj Nov 30, 2021
dcb6aba
Merge remote-tracking branch 'origin/cherry-pick2-for-2.15.0'
jonasfj Dec 1, 2021
0fc71db
Write log trace to $PUB_CACHE/log/pub_log.txt when crashing (#3240)
sigurdm Dec 3, 2021
2fd6b5f
Fix repository specification: isRetracted -> retracted (#3249)
jonasfj Dec 7, 2021
44b785a
Normalize file names for tar.gz (#3268)
sigurdm Jan 3, 2022
0a32ae4
folder/* should not ignore the folder itself, only the contents (#3267)
sigurdm Jan 3, 2022
17c5add
Error on acquireDependencies when the root pubspec has an unknown sdk…
sigurdm Jan 4, 2022
5bda798
Avoid race condition for hosted source on package extraction (#3277)
sigurdm Jan 10, 2022
1a298f4
Fix --verbose doc, and accept verboseness setting from embedder (#3279)
sigurdm Jan 10, 2022
6e03ec0
Support multiple packages in 'dart pub add' (#3283)
ArV29 Jan 18, 2022
8f5ab7b
Avoid raceconditions in `global activate`, `run` and `global run` (#3…
sigurdm Jan 20, 2022
a246141
Add flag controlling creation of `.packages` file. (#2757)
lrhn Jan 31, 2022
f27e90d
Upgrade other versions conservatively with --major-versions (#3295)
sigurdm Feb 1, 2022
a7e8e7f
merge
sigurdm Feb 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 3 additions & 28 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
include: package:pedantic/analysis_options.yaml
include: package:lints/recommended.yaml

analyzer:
errors:
Expand All @@ -12,52 +12,27 @@ analyzer:
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
- 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
2 changes: 1 addition & 1 deletion bin/dependency_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class DependencyServicesCommandRunner extends CommandRunner<int>
}

@override
log.Verbosity get verbosity => log.Verbosity.NORMAL;
log.Verbosity get verbosity => log.Verbosity.normal;
}

Future<void> main(List<String> arguments) async {
Expand Down
8 changes: 5 additions & 3 deletions doc/repository-spec-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ server, this could work in many different ways.
"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 */
Expand All @@ -236,7 +236,7 @@ server, this could work in many different ways.
"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 */
Expand Down Expand Up @@ -371,7 +371,9 @@ This can be used to forbid git-dependencies in published packages, limit the
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.

Expand Down
8 changes: 6 additions & 2 deletions lib/pub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ export 'src/pub_embeddable_command.dart' show PubAnalytics;
///
/// If [analytics] is given, pub will use that analytics instance to send
/// statistics about resolutions.
Command<int> pubCommand({PubAnalytics? analytics}) =>
PubEmbeddableCommand(analytics);
///
/// [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.')
Expand Down
43 changes: 16 additions & 27 deletions lib/src/authentication/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ 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';
Expand All @@ -22,14 +21,17 @@ class _AuthenticatedClient extends http.BaseClient {
/// 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 {
Expand All @@ -40,15 +42,16 @@ class _AuthenticatedClient extends http.BaseClient {
// 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;
Expand Down Expand Up @@ -124,31 +127,17 @@ Future<T> withAuthenticatedClient<T>(
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) {
var 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);
}
}
64 changes: 50 additions & 14 deletions lib/src/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ 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';
import 'entrypoint.dart';
import 'exceptions.dart';
import 'exit_codes.dart' as exit_codes;
import 'git.dart' as git;
import 'global_packages.dart';
import 'http.dart';
import 'io.dart';
import 'log.dart' as log;
import 'pub_embeddable_command.dart';
import 'sdk.dart';
Expand Down Expand Up @@ -56,7 +55,11 @@ abstract class PubCommand extends Command<int> {
return a;
}

String get directory => argResults['directory'] ?? _pubTopLevel.directory;
String get directory =>
(argResults.options.contains('directory')
? argResults['directory']
: null) ??
_pubTopLevel.directory;

late final SystemCache cache = SystemCache(isOffline: isOffline);

Expand Down Expand Up @@ -171,12 +174,11 @@ abstract class PubCommand extends Command<int> {
@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<void>(() async => runProtected(),
captureStackChains: _pubTopLevel.captureStackChains);
Expand All @@ -188,31 +190,61 @@ abstract class PubCommand extends Command<int> {
log.exception(error, chain);

if (_pubTopLevel.trace) {
log.dumpTranscript();
log.dumpTranscriptToStdErr();
} else if (!isUserFacingException(error)) {
log.error("""
This is an unexpected error. Please run
log.error('''
This is an unexpected error. The full log and other details are collected in:

dart pub --trace ${_topCommand.name} ${_topCommand.argResults!.arguments.map(protectArgument).join(' ')}
$transcriptPath

and include the logs in an issue on https://github.com/dart-lang/pub/issues/new
""");
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.
String protectArgument(String x) =>
RegExp(r'^[a-zA-Z0-9-_]+$').stringMatch(x) == null
? "'${x.replaceAll("'", r"'\''")}'"
: x;

late final Entrypoint? e;
try {
e = entrypoint;
} on ApplicationException {
e = null;
}
log.dumpTranscriptToFile(
transcriptPath,
'dart pub ${_topCommand.argResults!.arguments.map(protectArgument).join(' ')}',
e,
);

if (!crashed) {
log.message('Logs written to $transcriptPath.');
}
}
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 ||
Expand Down Expand Up @@ -282,6 +314,10 @@ and include the logs in an issue on https://github.com/dart-lang/pub/issues/new
}
_command = list.join(' ');
}

String get transcriptPath {
return p.join(cache.rootDir, 'log', 'pub_log.txt');
}
}

abstract class PubTopLevel {
Expand Down
Loading