Unverified Commit 8df0d686 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] remove globals from pub (#55412)

parent cbc121e3
...@@ -205,7 +205,7 @@ class PackagesPublishCommand extends FlutterCommand { ...@@ -205,7 +205,7 @@ class PackagesPublishCommand extends FlutterCommand {
if (boolArg('force')) '--force', if (boolArg('force')) '--force',
]; ];
Cache.releaseLockEarly(); Cache.releaseLockEarly();
await pub.interactively(<String>['publish', ...args]); await pub.interactively(<String>['publish', ...args], stdio: globals.stdio);
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
} }
...@@ -236,7 +236,7 @@ class PackagesForwardCommand extends FlutterCommand { ...@@ -236,7 +236,7 @@ class PackagesForwardCommand extends FlutterCommand {
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
Cache.releaseLockEarly(); Cache.releaseLockEarly();
await pub.interactively(<String>[_commandName, ...argResults.rest]); await pub.interactively(<String>[_commandName, ...argResults.rest], stdio: globals.stdio);
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
...@@ -264,7 +264,7 @@ class PackagesPassthroughCommand extends FlutterCommand { ...@@ -264,7 +264,7 @@ class PackagesPassthroughCommand extends FlutterCommand {
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
Cache.releaseLockEarly(); Cache.releaseLockEarly();
await pub.interactively(argResults.rest); await pub.interactively(argResults.rest, stdio: globals.stdio);
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
} }
...@@ -167,7 +167,14 @@ Future<T> runInContext<T>( ...@@ -167,7 +167,14 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
), ),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
botDetector: globals.botDetector,
platform: globals.platform,
usage: globals.flutterUsage,
),
ShutdownHooks: () => ShutdownHooks(logger: globals.logger), ShutdownHooks: () => ShutdownHooks(logger: globals.logger),
Signals: () => Signals(), Signals: () => Signals(),
Stdio: () => Stdio(), Stdio: () => Stdio(),
......
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import '../base/bot_detector.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
...@@ -13,14 +16,19 @@ import '../base/io.dart' as io; ...@@ -13,14 +16,19 @@ import '../base/io.dart' as io;
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../cache.dart'; import '../cache.dart';
import '../globals.dart' as globals;
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
import 'sdk.dart';
/// The [Pub] instance. /// The [Pub] instance.
Pub get pub => context.get<Pub>(); Pub get pub => context.get<Pub>();
/// The console environment key used by the pub tool.
const String _kPubEnvironmentKey = 'PUB_ENVIRONMENT';
/// The console environment key used by the pub tool to find the cache directory.
const String _kPubCacheEnvironmentKey = 'PUB_CACHE';
typedef MessageFilter = String Function(String message);
/// Represents Flutter-specific data that is added to the `PUB_ENVIRONMENT` /// Represents Flutter-specific data that is added to the `PUB_ENVIRONMENT`
/// environment variable and allows understanding the type of requests made to /// environment variable and allows understanding the type of requests made to
/// the package site on Flutter's behalf. /// the package site on Flutter's behalf.
...@@ -47,7 +55,6 @@ class PubContext { ...@@ -47,7 +55,6 @@ class PubContext {
static final PubContext pubUpgrade = PubContext._(<String>['upgrade']); static final PubContext pubUpgrade = PubContext._(<String>['upgrade']);
static final PubContext pubForward = PubContext._(<String>['forward']); static final PubContext pubForward = PubContext._(<String>['forward']);
static final PubContext runTest = PubContext._(<String>['run_test']); static final PubContext runTest = PubContext._(<String>['run_test']);
static final PubContext flutterTests = PubContext._(<String>['flutter_tests']); static final PubContext flutterTests = PubContext._(<String>['flutter_tests']);
static final PubContext updatePackages = PubContext._(<String>['update_packages']); static final PubContext updatePackages = PubContext._(<String>['update_packages']);
...@@ -63,26 +70,17 @@ class PubContext { ...@@ -63,26 +70,17 @@ class PubContext {
} }
} }
bool _shouldRunPubGet({ File pubSpecYaml, File dotPackages }) {
if (!dotPackages.existsSync()) {
return true;
}
final DateTime dotPackagesLastModified = dotPackages.lastModifiedSync();
if (pubSpecYaml.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true;
}
final File flutterToolsStamp = globals.cache.getStampFileFor('flutter_tools');
if (flutterToolsStamp.existsSync() &&
flutterToolsStamp.lastModifiedSync().isAfter(dotPackagesLastModified)) {
return true;
}
return false;
}
/// A handle for interacting with the pub tool. /// A handle for interacting with the pub tool.
abstract class Pub { abstract class Pub {
/// Create a default [Pub] instance. /// Create a default [Pub] instance.
const factory Pub() = _DefaultPub; factory Pub({
@required FileSystem fileSystem,
@required Logger logger,
@required ProcessManager processManager,
@required Platform platform,
@required BotDetector botDetector,
@required Usage usage,
}) = _DefaultPub;
/// Runs `pub get`. /// Runs `pub get`.
/// ///
...@@ -129,11 +127,34 @@ abstract class Pub { ...@@ -129,11 +127,34 @@ abstract class Pub {
Future<void> interactively( Future<void> interactively(
List<String> arguments, { List<String> arguments, {
String directory, String directory,
@required io.Stdio stdio,
}); });
} }
class _DefaultPub implements Pub { class _DefaultPub implements Pub {
const _DefaultPub(); _DefaultPub({
@required FileSystem fileSystem,
@required Logger logger,
@required ProcessManager processManager,
@required Platform platform,
@required BotDetector botDetector,
@required Usage usage,
}) : _fileSystem = fileSystem,
_logger = logger,
_platform = platform,
_botDetector = botDetector,
_usage = usage,
_processUtils = ProcessUtils(
logger: logger,
processManager: processManager,
);
final FileSystem _fileSystem;
final Logger _logger;
final ProcessUtils _processUtils;
final Platform _platform;
final BotDetector _botDetector;
final Usage _usage;
@override @override
Future<void> get({ Future<void> get({
...@@ -146,10 +167,12 @@ class _DefaultPub implements Pub { ...@@ -146,10 +167,12 @@ class _DefaultPub implements Pub {
bool skipPubspecYamlCheck = false, bool skipPubspecYamlCheck = false,
String flutterRootOverride, String flutterRootOverride,
}) async { }) async {
directory ??= globals.fs.currentDirectory.path; directory ??= _fileSystem.currentDirectory.path;
final File pubSpecYaml = globals.fs.file(globals.fs.path.join(directory, 'pubspec.yaml')); final File pubSpecYaml = _fileSystem.file(
final File dotPackages = globals.fs.file(globals.fs.path.join(directory, '.packages')); _fileSystem.path.join(directory, 'pubspec.yaml'));
final File packageConfigFile = _fileSystem.file(
_fileSystem.path.join(directory, '.dart_tool', 'package_config.json'));
if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) { if (!skipPubspecYamlCheck && !pubSpecYaml.existsSync()) {
if (!skipIfAbsent) { if (!skipIfAbsent) {
...@@ -160,24 +183,33 @@ class _DefaultPub implements Pub { ...@@ -160,24 +183,33 @@ class _DefaultPub implements Pub {
final DateTime originalPubspecYamlModificationTime = pubSpecYaml.lastModifiedSync(); final DateTime originalPubspecYamlModificationTime = pubSpecYaml.lastModifiedSync();
if (!checkLastModified || _shouldRunPubGet(pubSpecYaml: pubSpecYaml, dotPackages: dotPackages)) { if (!checkLastModified || _shouldRunPubGet(
pubSpecYaml: pubSpecYaml,
packageConfigFile: packageConfigFile,
)) {
final String command = upgrade ? 'upgrade' : 'get'; final String command = upgrade ? 'upgrade' : 'get';
final Status status = globals.logger.startProgress( final Status status = _logger.startProgress(
'Running "flutter pub $command" in ${globals.fs.path.basename(directory)}...', 'Running "flutter pub $command" in ${_fileSystem.path.basename(directory)}...',
timeout: timeoutConfiguration.slowOperation, timeout: const TimeoutConfiguration().slowOperation,
); );
final bool verbose = FlutterCommand.current != null && FlutterCommand.current.globalResults['verbose'] as bool; final bool verbose = _logger.isVerbose;
final List<String> args = <String>[ final List<String> args = <String>[
if (verbose) '--verbose' else '--verbosity=warning', if (verbose)
...<String>[command, '--no-precompile'], '--verbose'
if (offline) '--offline', else
'--verbosity=warning',
...<String>[
command,
'--no-precompile',
],
if (offline)
'--offline',
]; ];
try { try {
await batch( await batch(
args, args,
context: context, context: context,
directory: directory, directory: directory,
filter: _filterOverrideWarnings,
failureMessage: 'pub $command failed', failureMessage: 'pub $command failed',
retry: true, retry: true,
flutterRootOverride: flutterRootOverride, flutterRootOverride: flutterRootOverride,
...@@ -190,11 +222,13 @@ class _DefaultPub implements Pub { ...@@ -190,11 +222,13 @@ class _DefaultPub implements Pub {
} }
} }
if (!dotPackages.existsSync()) { if (!packageConfigFile.existsSync()) {
throwToolExit('$directory: pub did not create .packages file.'); throwToolExit('$directory: pub did not create .packages file.');
} }
if (pubSpecYaml.lastModifiedSync() != originalPubspecYamlModificationTime) { if (pubSpecYaml.lastModifiedSync() != originalPubspecYamlModificationTime) {
throwToolExit('$directory: unexpected concurrent modification of pubspec.yaml while running pub.'); throwToolExit(
'$directory: unexpected concurrent modification of '
'pubspec.yaml while running pub.');
} }
// We don't check if dotPackages was actually modified, because as far as we can tell sometimes // We don't check if dotPackages was actually modified, because as far as we can tell sometimes
// pub will decide it does not need to actually modify it. // pub will decide it does not need to actually modify it.
...@@ -202,29 +236,28 @@ class _DefaultPub implements Pub { ...@@ -202,29 +236,28 @@ class _DefaultPub implements Pub {
// file to be more recently modified. // file to be more recently modified.
final DateTime now = DateTime.now(); final DateTime now = DateTime.now();
if (now.isBefore(originalPubspecYamlModificationTime)) { if (now.isBefore(originalPubspecYamlModificationTime)) {
globals.printError( _logger.printError(
'Warning: File "${globals.fs.path.absolute(pubSpecYaml.path)}" was created in the future. ' 'Warning: File "${_fileSystem.path.absolute(pubSpecYaml.path)}" was created in the future. '
'Optimizations that rely on comparing time stamps will be unreliable. Check your ' 'Optimizations that rely on comparing time stamps will be unreliable. Check your '
'system clock for accuracy.\n' 'system clock for accuracy.\n'
'The timestamp was: $originalPubspecYamlModificationTime\n' 'The timestamp was: $originalPubspecYamlModificationTime\n'
'The time now is: $now' 'The time now is: $now'
); );
} else { } else {
dotPackages.setLastModifiedSync(now); packageConfigFile.setLastModifiedSync(now);
final DateTime newDotPackagesTimestamp = dotPackages.lastModifiedSync(); final DateTime newDotPackagesTimestamp = packageConfigFile.lastModifiedSync();
if (newDotPackagesTimestamp.isBefore(originalPubspecYamlModificationTime)) { if (newDotPackagesTimestamp.isBefore(originalPubspecYamlModificationTime)) {
globals.printError( _logger.printError(
'Warning: Failed to set timestamp of "${globals.fs.path.absolute(dotPackages.path)}". ' 'Warning: Failed to set timestamp of "${_fileSystem.path.absolute(packageConfigFile.path)}". '
'Tried to set timestamp to $now, but new timestamp is $newDotPackagesTimestamp.' 'Tried to set timestamp to $now, but new timestamp is $newDotPackagesTimestamp.'
); );
if (newDotPackagesTimestamp.isAfter(now)) { if (newDotPackagesTimestamp.isAfter(now)) {
globals.printError('Maybe the file was concurrently modified?'); _logger.printError('Maybe the file was concurrently modified?');
} }
} }
} }
} }
@override @override
Future<void> batch( Future<void> batch(
List<String> arguments, { List<String> arguments, {
...@@ -236,7 +269,7 @@ class _DefaultPub implements Pub { ...@@ -236,7 +269,7 @@ class _DefaultPub implements Pub {
bool showTraceForErrors, bool showTraceForErrors,
String flutterRootOverride, String flutterRootOverride,
}) async { }) async {
showTraceForErrors ??= await globals.isRunningOnBot; showTraceForErrors ??= await _botDetector.isRunningOnBot;
String lastPubMessage = 'no message'; String lastPubMessage = 'no message';
bool versionSolvingFailed = false; bool versionSolvingFailed = false;
...@@ -259,7 +292,7 @@ class _DefaultPub implements Pub { ...@@ -259,7 +292,7 @@ class _DefaultPub implements Pub {
int code; int code;
loop: while (true) { loop: while (true) {
attempts += 1; attempts += 1;
code = await processUtils.stream( code = await _processUtils.stream(
_pubCommand(arguments), _pubCommand(arguments),
workingDirectory: directory, workingDirectory: directory,
mapFunction: filterWrapper, // may set versionSolvingFailed, lastPubMessage mapFunction: filterWrapper, // may set versionSolvingFailed, lastPubMessage
...@@ -275,7 +308,10 @@ class _DefaultPub implements Pub { ...@@ -275,7 +308,10 @@ class _DefaultPub implements Pub {
} }
assert(message != null); assert(message != null);
versionSolvingFailed = false; versionSolvingFailed = false;
globals.printStatus('$failureMessage ($message) -- attempting retry $attempts in $duration second${ duration == 1 ? "" : "s"}...'); _logger.printStatus(
'$failureMessage ($message) -- attempting retry $attempts in $duration '
'second${ duration == 1 ? "" : "s"}...',
);
await Future<void>.delayed(Duration(seconds: duration)); await Future<void>.delayed(Duration(seconds: duration));
if (duration < 64) { if (duration < 64) {
duration *= 2; duration *= 2;
...@@ -292,6 +328,7 @@ class _DefaultPub implements Pub { ...@@ -292,6 +328,7 @@ class _DefaultPub implements Pub {
PubResultEvent( PubResultEvent(
context: context.toAnalyticsString(), context: context.toAnalyticsString(),
result: result, result: result,
usage: _usage,
).send(); ).send();
if (code != 0) { if (code != 0) {
...@@ -303,33 +340,34 @@ class _DefaultPub implements Pub { ...@@ -303,33 +340,34 @@ class _DefaultPub implements Pub {
Future<void> interactively( Future<void> interactively(
List<String> arguments, { List<String> arguments, {
String directory, String directory,
@required io.Stdio stdio,
}) async { }) async {
Cache.releaseLockEarly(); Cache.releaseLockEarly();
final io.Process process = await processUtils.start( final io.Process process = await _processUtils.start(
_pubCommand(arguments), _pubCommand(arguments),
workingDirectory: directory, workingDirectory: directory,
environment: await _createPubEnvironment(PubContext.interactive), environment: await _createPubEnvironment(PubContext.interactive),
); );
// Pipe the Flutter tool stdin to the pub stdin. // Pipe the Flutter tool stdin to the pub stdin.
unawaited(process.stdin.addStream(globals.stdio.stdin) unawaited(process.stdin.addStream(stdio.stdin)
// If pub exits unexpectedly with an error, that will be reported below // If pub exits unexpectedly with an error, that will be reported below
// by the tool exit after the exit code check. // by the tool exit after the exit code check.
.catchError((dynamic err, StackTrace stack) { .catchError((dynamic err, StackTrace stack) {
globals.printTrace('Echoing stdin to the pub subprocess failed:'); _logger.printTrace('Echoing stdin to the pub subprocess failed:');
globals.printTrace('$err\n$stack'); _logger.printTrace('$err\n$stack');
} }
)); ));
// Pipe the pub stdout and stderr to the tool stdout and stderr. // Pipe the pub stdout and stderr to the tool stdout and stderr.
try { try {
await Future.wait<dynamic>(<Future<dynamic>>[ await Future.wait<dynamic>(<Future<dynamic>>[
globals.stdio.addStdoutStream(process.stdout), stdio.addStdoutStream(process.stdout),
globals.stdio.addStderrStream(process.stderr), stdio.addStderrStream(process.stderr),
]); ]);
} on Exception catch (err, stack) { } on Exception catch (err, stack) {
globals.printTrace('Echoing stdout or stderr from the pub subprocess failed:'); _logger.printTrace('Echoing stdout or stderr from the pub subprocess failed:');
globals.printTrace('$err\n$stack'); _logger.printTrace('$err\n$stack');
} }
// Wait for pub to exit. // Wait for pub to exit.
...@@ -341,81 +379,79 @@ class _DefaultPub implements Pub { ...@@ -341,81 +379,79 @@ class _DefaultPub implements Pub {
/// The command used for running pub. /// The command used for running pub.
List<String> _pubCommand(List<String> arguments) { List<String> _pubCommand(List<String> arguments) {
return <String>[sdkBinaryName('pub'), ...arguments]; // TODO(jonahwilliams): refactor to use artifacts.
final String sdkPath = _fileSystem.path.joinAll(<String>[
Cache.flutterRoot,
'bin',
'cache',
'dart-sdk',
'bin',
if (_platform.isWindows)
'pub.bat'
else
'pub'
]);
return <String>[sdkPath, ...arguments];
} }
} bool _shouldRunPubGet({ @required File pubSpecYaml, @required File packageConfigFile }) {
if (!packageConfigFile.existsSync()) {
typedef MessageFilter = String Function(String message); return true;
}
/// The full environment used when running pub. final DateTime dotPackagesLastModified = packageConfigFile.lastModifiedSync();
/// if (pubSpecYaml.lastModifiedSync().isAfter(dotPackagesLastModified)) {
/// [context] provides extra information to package server requests to return true;
/// understand usage. }
Future<Map<String, String>> _createPubEnvironment(PubContext context, [ String flutterRootOverride ]) async { return false;
final Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': flutterRootOverride ?? Cache.flutterRoot,
_pubEnvironmentKey: await _getPubEnvironmentValue(context),
};
final String pubCache = _getRootPubCacheIfAvailable();
if (pubCache != null) {
environment[_pubCacheEnvironmentKey] = pubCache;
} }
return environment;
}
final RegExp _analyzerWarning = RegExp(r'^! \w+ [^ ]+ from path \.\./\.\./bin/cache/dart-sdk/lib/\w+$');
/// The console environment key used by the pub tool.
const String _pubEnvironmentKey = 'PUB_ENVIRONMENT';
/// The console environment key used by the pub tool to find the cache directory. // Returns the environment value that should be used when running pub.
const String _pubCacheEnvironmentKey = 'PUB_CACHE'; //
// Includes any existing environment variable, if one exists.
/// Returns the environment value that should be used when running pub. //
/// // [context] provides extra information to package server requests to
/// Includes any existing environment variable, if one exists. // understand usage.
/// Future<String> _getPubEnvironmentValue(PubContext pubContext) async {
/// [context] provides extra information to package server requests to // DO NOT update this function without contacting kevmoo.
/// understand usage. // We have server-side tooling that assumes the values are consistent.
Future<String> _getPubEnvironmentValue(PubContext pubContext) async { final String existing = _platform.environment[_kPubEnvironmentKey];
// DO NOT update this function without contacting kevmoo. final List<String> values = <String>[
// We have server-side tooling that assumes the values are consistent. if (existing != null && existing.isNotEmpty) existing,
final String existing = globals.platform.environment[_pubEnvironmentKey]; if (await _botDetector.isRunningOnBot) 'flutter_bot',
final List<String> values = <String>[ 'flutter_cli',
if (existing != null && existing.isNotEmpty) existing, ...pubContext._values,
if (await globals.isRunningOnBot) 'flutter_bot', ];
'flutter_cli', return values.join(':');
...pubContext._values,
];
return values.join(':');
}
String _getRootPubCacheIfAvailable() {
if (globals.platform.environment.containsKey(_pubCacheEnvironmentKey)) {
return globals.platform.environment[_pubCacheEnvironmentKey];
} }
final String cachePath = globals.fs.path.join(Cache.flutterRoot, '.pub-cache'); String _getRootPubCacheIfAvailable() {
if (globals.fs.directory(cachePath).existsSync()) { if (_platform.environment.containsKey(_kPubCacheEnvironmentKey)) {
globals.printTrace('Using $cachePath for the pub cache.'); return _platform.environment[_kPubCacheEnvironmentKey];
return cachePath; }
}
// Use pub's default location by returning null. final String cachePath = _fileSystem.path.join(Cache.flutterRoot, '.pub-cache');
return null; if (_fileSystem.directory(cachePath).existsSync()) {
} _logger.printTrace('Using $cachePath for the pub cache.');
return cachePath;
}
String _filterOverrideWarnings(String message) { // Use pub's default location by returning null.
// This function filters out these three messages:
// Warning: You are using these overridden dependencies:
// ! analyzer 0.29.0-alpha.0 from path ../../bin/cache/dart-sdk/lib/analyzer
// ! front_end 0.1.0-alpha.0 from path ../../bin/cache/dart-sdk/lib/front_end
if (message == 'Warning: You are using these overridden dependencies:') {
return null; return null;
} }
if (message.contains(_analyzerWarning)) {
return null; /// The full environment used when running pub.
///
/// [context] provides extra information to package server requests to
/// understand usage.
Future<Map<String, String>> _createPubEnvironment(PubContext context, [ String flutterRootOverride ]) async {
final Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': flutterRootOverride ?? Cache.flutterRoot,
_kPubEnvironmentKey: await _getPubEnvironmentValue(context),
};
final String pubCache = _getRootPubCacheIfAvailable();
if (pubCache != null) {
environment[_kPubCacheEnvironmentKey] = pubCache;
}
return environment;
} }
return message;
} }
...@@ -129,7 +129,8 @@ class PubResultEvent extends UsageEvent { ...@@ -129,7 +129,8 @@ class PubResultEvent extends UsageEvent {
PubResultEvent({ PubResultEvent({
@required String context, @required String context,
@required String result, @required String result,
}) : super('pub-result', context, label: result, flutterUsage: globals.flutterUsage); @required Usage usage,
}) : super('pub-result', context, label: result, flutterUsage: usage);
} }
/// An event that reports something about a build. /// An event that reports something about a build.
......
...@@ -15,6 +15,7 @@ import 'package:flutter_tools/src/dart/sdk.dart'; ...@@ -15,6 +15,7 @@ import 'package:flutter_tools/src/dart/sdk.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
...@@ -65,7 +66,15 @@ void main() { ...@@ -65,7 +66,15 @@ void main() {
testUsingContext('AnalysisServer success', () async { testUsingContext('AnalysisServer success', () async {
_createSampleProject(tempDir); _createSampleProject(tempDir);
await const Pub().get(context: PubContext.flutterTests, directory: tempDir.path); final Pub pub = Pub(
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
platform: const LocalPlatform(),
botDetector: globals.botDetector,
usage: globals.flutterUsage,
);
await pub.get(context: PubContext.flutterTests, directory: tempDir.path);
server = AnalysisServer(dartSdkPath, <String>[tempDir.path], server = AnalysisServer(dartSdkPath, <String>[tempDir.path],
fileSystem: fileSystem, fileSystem: fileSystem,
...@@ -90,7 +99,15 @@ void main() { ...@@ -90,7 +99,15 @@ void main() {
testUsingContext('AnalysisServer errors', () async { testUsingContext('AnalysisServer errors', () async {
_createSampleProject(tempDir, brokenCode: true); _createSampleProject(tempDir, brokenCode: true);
await const Pub().get(context: PubContext.flutterTests, directory: tempDir.path); final Pub pub = Pub(
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
platform: const LocalPlatform(),
usage: globals.flutterUsage,
botDetector: globals.botDetector,
);
await pub.get(context: PubContext.flutterTests, directory: tempDir.path);
server = AnalysisServer(dartSdkPath, <String>[tempDir.path], server = AnalysisServer(dartSdkPath, <String>[tempDir.path],
fileSystem: fileSystem, fileSystem: fileSystem,
......
...@@ -86,7 +86,14 @@ void main() { ...@@ -86,7 +86,14 @@ void main() {
); );
return _runFlutterTest(projectDir); return _runFlutterTest(projectDir);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('can create a default project if empty directory exists', () async { testUsingContext('can create a default project if empty directory exists', () async {
...@@ -104,7 +111,14 @@ void main() { ...@@ -104,7 +111,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('creates a module project correctly', () async { testUsingContext('creates a module project correctly', () async {
...@@ -126,7 +140,14 @@ void main() { ...@@ -126,7 +140,14 @@ void main() {
]); ]);
return _runFlutterTest(projectDir); return _runFlutterTest(projectDir);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('cannot create a project if non-empty non-project directory exists with .metadata', () async { testUsingContext('cannot create a project if non-empty non-project directory exists with .metadata', () async {
...@@ -144,7 +165,14 @@ void main() { ...@@ -144,7 +165,14 @@ void main() {
]), ]),
throwsToolExit(message: 'Sorry, unable to detect the type of project to recreate')); throwsToolExit(message: 'Sorry, unable to detect the type of project to recreate'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
...noColorTerminalOverride, ...noColorTerminalOverride,
}); });
...@@ -170,7 +198,14 @@ void main() { ...@@ -170,7 +198,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('detects and recreates an app project correctly', () async { testUsingContext('detects and recreates an app project correctly', () async {
...@@ -195,7 +230,14 @@ void main() { ...@@ -195,7 +230,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('detects and recreates a plugin project correctly', () async { testUsingContext('detects and recreates a plugin project correctly', () async {
...@@ -220,7 +262,14 @@ void main() { ...@@ -220,7 +262,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('detects and recreates a package project correctly', () async { testUsingContext('detects and recreates a package project correctly', () async {
...@@ -251,7 +300,14 @@ void main() { ...@@ -251,7 +300,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('kotlin/swift legacy app project', () async { testUsingContext('kotlin/swift legacy app project', () async {
...@@ -273,7 +329,14 @@ void main() { ...@@ -273,7 +329,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('can create a package project', () async { testUsingContext('can create a package project', () async {
...@@ -303,7 +366,14 @@ void main() { ...@@ -303,7 +366,14 @@ void main() {
); );
return _runFlutterTest(projectDir); return _runFlutterTest(projectDir);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('can create a plugin project', () async { testUsingContext('can create a plugin project', () async {
...@@ -325,7 +395,14 @@ void main() { ...@@ -325,7 +395,14 @@ void main() {
); );
return _runFlutterTest(projectDir.childDirectory('example')); return _runFlutterTest(projectDir.childDirectory('example'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('plugin example app depends on plugin', () async { testUsingContext('plugin example app depends on plugin', () async {
...@@ -344,7 +421,14 @@ void main() { ...@@ -344,7 +421,14 @@ void main() {
final PathDependency pathDependency = pubspec.dependencies[pluginName] as PathDependency; final PathDependency pathDependency = pubspec.dependencies[pluginName] as PathDependency;
expect(pathDependency.path, '../'); expect(pathDependency.path, '../');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('kotlin/swift plugin project', () async { testUsingContext('kotlin/swift plugin project', () async {
...@@ -429,7 +513,14 @@ void main() { ...@@ -429,7 +513,14 @@ void main() {
<String>['lib/main.dart'], <String>['lib/main.dart'],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('module project with pub', () async { testUsingContext('module project with pub', () async {
...@@ -464,7 +555,14 @@ void main() { ...@@ -464,7 +555,14 @@ void main() {
'.android/Flutter/src/main/java/io/flutter/facade/Flutter.java', '.android/Flutter/src/main/java/io/flutter/facade/Flutter.java',
]); ]);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
...@@ -1038,7 +1136,14 @@ void main() { ...@@ -1038,7 +1136,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('can re-gen module .ios/ folder, reusing custom org', () async { testUsingContext('can re-gen module .ios/ folder, reusing custom org', () async {
...@@ -1055,7 +1160,14 @@ void main() { ...@@ -1055,7 +1160,14 @@ void main() {
'com.bar.foo.flutterProject', 'com.bar.foo.flutterProject',
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('can re-gen app android/ folder, reusing custom org', () async { testUsingContext('can re-gen app android/ folder, reusing custom org', () async {
...@@ -1210,7 +1322,14 @@ void main() { ...@@ -1210,7 +1322,14 @@ void main() {
], ],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext( testUsingContext(
...@@ -1227,7 +1346,14 @@ void main() { ...@@ -1227,7 +1346,14 @@ void main() {
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
ProcessManager: () => loggingProcessManager, ProcessManager: () => loggingProcessManager,
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}, },
); );
...@@ -1245,7 +1371,14 @@ void main() { ...@@ -1245,7 +1371,14 @@ void main() {
}, },
overrides: <Type, Generator>{ overrides: <Type, Generator>{
ProcessManager: () => loggingProcessManager, ProcessManager: () => loggingProcessManager,
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}, },
); );
......
...@@ -195,7 +195,14 @@ void main() { ...@@ -195,7 +195,14 @@ void main() {
expectDependenciesResolved(projectPath); expectDependenciesResolved(projectPath);
expectZeroPluginsInjected(projectPath); expectZeroPluginsInjected(projectPath);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('get --offline fetches packages', () async { testUsingContext('get --offline fetches packages', () async {
...@@ -208,7 +215,14 @@ void main() { ...@@ -208,7 +215,14 @@ void main() {
expectDependenciesResolved(projectPath); expectDependenciesResolved(projectPath);
expectZeroPluginsInjected(projectPath); expectZeroPluginsInjected(projectPath);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('set the number of plugins as usage value', () async { testUsingContext('set the number of plugins as usage value', () async {
...@@ -222,7 +236,14 @@ void main() { ...@@ -222,7 +236,14 @@ void main() {
expect(await getCommand.usageValues, expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesNumberPlugins, '0')); containsPair(CustomDimensions.commandPackagesNumberPlugins, '0'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('indicate that the project is not a module in usage value', () async { testUsingContext('indicate that the project is not a module in usage value', () async {
...@@ -236,7 +257,14 @@ void main() { ...@@ -236,7 +257,14 @@ void main() {
expect(await getCommand.usageValues, expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesProjectModule, 'false')); containsPair(CustomDimensions.commandPackagesProjectModule, 'false'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('indicate that the project is a module in usage value', () async { testUsingContext('indicate that the project is a module in usage value', () async {
...@@ -250,7 +278,14 @@ void main() { ...@@ -250,7 +278,14 @@ void main() {
expect(await getCommand.usageValues, expect(await getCommand.usageValues,
containsPair(CustomDimensions.commandPackagesProjectModule, 'true')); containsPair(CustomDimensions.commandPackagesProjectModule, 'true'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('indicate that Android project reports v1 in usage value', () async { testUsingContext('indicate that Android project reports v1 in usage value', () async {
...@@ -265,7 +300,14 @@ void main() { ...@@ -265,7 +300,14 @@ void main() {
containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v1')); containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v1'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: false), FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: false),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('indicate that Android project reports v2 in usage value', () async { testUsingContext('indicate that Android project reports v2 in usage value', () async {
...@@ -280,7 +322,14 @@ void main() { ...@@ -280,7 +322,14 @@ void main() {
containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v2')); containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v2'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: true), FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: true),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('upgrade fetches packages', () async { testUsingContext('upgrade fetches packages', () async {
...@@ -293,7 +342,14 @@ void main() { ...@@ -293,7 +342,14 @@ void main() {
expectDependenciesResolved(projectPath); expectDependenciesResolved(projectPath);
expectZeroPluginsInjected(projectPath); expectZeroPluginsInjected(projectPath);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('get fetches packages and injects plugin', () async { testUsingContext('get fetches packages and injects plugin', () async {
...@@ -306,7 +362,14 @@ void main() { ...@@ -306,7 +362,14 @@ void main() {
expectDependenciesResolved(projectPath); expectDependenciesResolved(projectPath);
expectModulePluginInjected(projectPath); expectModulePluginInjected(projectPath);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('get fetches packages and injects plugin in plugin project', () async { testUsingContext('get fetches packages and injects plugin in plugin project', () async {
...@@ -327,7 +390,14 @@ void main() { ...@@ -327,7 +390,14 @@ void main() {
expectDependenciesResolved(exampleProjectPath); expectDependenciesResolved(exampleProjectPath);
expectPluginInjected(exampleProjectPath); expectPluginInjected(exampleProjectPath);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
}); });
...@@ -351,7 +421,14 @@ void main() { ...@@ -351,7 +421,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysFalseBotDetector(), BotDetector: () => const AlwaysFalseBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('test with bot', () async { testUsingContext('test with bot', () async {
...@@ -366,7 +443,14 @@ void main() { ...@@ -366,7 +443,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('run', () async { testUsingContext('run', () async {
...@@ -380,7 +464,14 @@ void main() { ...@@ -380,7 +464,14 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('pub publish', () async { testUsingContext('pub publish', () async {
...@@ -405,7 +496,14 @@ void main() { ...@@ -405,7 +496,14 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('pub publish input fails', () async { testUsingContext('pub publish input fails', () async {
...@@ -426,7 +524,14 @@ void main() { ...@@ -426,7 +524,14 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('publish', () async { testUsingContext('publish', () async {
...@@ -439,7 +544,14 @@ void main() { ...@@ -439,7 +544,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('packages publish', () async { testUsingContext('packages publish', () async {
...@@ -452,7 +564,14 @@ void main() { ...@@ -452,7 +564,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('deps', () async { testUsingContext('deps', () async {
...@@ -465,7 +584,14 @@ void main() { ...@@ -465,7 +584,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('cache', () async { testUsingContext('cache', () async {
...@@ -478,7 +604,14 @@ void main() { ...@@ -478,7 +604,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('version', () async { testUsingContext('version', () async {
...@@ -491,7 +624,14 @@ void main() { ...@@ -491,7 +624,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('uploader', () async { testUsingContext('uploader', () async {
...@@ -504,7 +644,14 @@ void main() { ...@@ -504,7 +644,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('global', () async { testUsingContext('global', () async {
...@@ -518,7 +665,14 @@ void main() { ...@@ -518,7 +665,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
testUsingContext('outdated', () async { testUsingContext('outdated', () async {
...@@ -531,7 +685,14 @@ void main() { ...@@ -531,7 +685,14 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Stdio: () => mockStdio, Stdio: () => mockStdio,
BotDetector: () => const AlwaysTrueBotDetector(), BotDetector: () => const AlwaysTrueBotDetector(),
Pub: () => const Pub(), Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
}); });
}); });
} }
...@@ -3,73 +3,81 @@ ...@@ -3,73 +3,81 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:quiver/testing/async.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/bot_detector.dart'; import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/dart/pub.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:quiver/testing/async.dart';
import 'package:platform/platform.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart' as mocks; import '../../src/mocks.dart' as mocks;
import '../../src/testbed.dart';
void main() { void main() {
setUpAll(() { setUpAll(() {
Cache.flutterRoot = getFlutterRoot(); Cache.flutterRoot = '';
}); });
tearDown(() { tearDown(() {
MockDirectory.findCache = false; MockDirectory.findCache = false;
}); });
testUsingContext('pub get 69', () async { testWithoutContext('pub get 69', () async {
String error; String error;
final MockProcessManager processMock = context.get<ProcessManager>() as MockProcessManager; final MockProcessManager processMock = MockProcessManager(69);
final BufferLogger logger = BufferLogger.test();
final Pub pub = Pub(
fileSystem: MockFileSystem(),
logger: logger,
processManager: processMock,
usage: MockUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
botDetector: const BotDetectorAlwaysNo(),
);
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
expect(processMock.lastPubEnvironment, isNull); expect(processMock.lastPubEnvironment, isNull);
expect(testLogger.statusText, ''); expect(logger.statusText, '');
pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) { pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
}); });
time.elapse(const Duration(milliseconds: 500)); time.elapse(const Duration(milliseconds: 500));
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n', 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n',
); );
expect(processMock.lastPubEnvironment, contains('flutter_cli:flutter_tests')); expect(processMock.lastPubEnvironment, contains('flutter_cli:flutter_tests'));
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
time.elapse(const Duration(milliseconds: 500)); time.elapse(const Duration(milliseconds: 500));
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n' 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n', 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n',
); );
time.elapse(const Duration(seconds: 1)); time.elapse(const Duration(seconds: 1));
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n' 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n', 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n',
); );
time.elapse(const Duration(seconds: 100)); // from t=0 to t=100 time.elapse(const Duration(seconds: 100)); // from t=0 to t=100
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n' 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n' 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n'
...@@ -80,7 +88,7 @@ void main() { ...@@ -80,7 +88,7 @@ void main() {
'pub get failed (server unavailable) -- attempting retry 7 in 64 seconds...\n', // at t=61 'pub get failed (server unavailable) -- attempting retry 7 in 64 seconds...\n', // at t=61
); );
time.elapse(const Duration(seconds: 200)); // from t=0 to t=200 time.elapse(const Duration(seconds: 200)); // from t=0 to t=200
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n' 'pub get failed (server unavailable) -- attempting retry 1 in 1 second...\n'
'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n' 'pub get failed (server unavailable) -- attempting retry 2 in 2 seconds...\n'
...@@ -94,49 +102,51 @@ void main() { ...@@ -94,49 +102,51 @@ void main() {
'pub get failed (server unavailable) -- attempting retry 10 in 64 seconds...\n', // at t=167 'pub get failed (server unavailable) -- attempting retry 10 in 64 seconds...\n', // at t=167
); );
}); });
expect(testLogger.errorText, isEmpty); expect(logger.errorText, isEmpty);
expect(error, isNull); expect(error, isNull);
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(69),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{}),
),
Pub: () => const Pub(),
}); });
testUsingContext('pub get 66 shows message from pub', () async { testWithoutContext('pub get 66 shows message from pub', () async {
final BufferLogger logger = BufferLogger.test();
final Pub pub = Pub(
platform: FakePlatform(environment: const <String, String>{}),
fileSystem: MockFileSystem(),
logger: logger,
usage: MockUsage(),
botDetector: const BotDetectorAlwaysNo(),
processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
);
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
throw AssertionError('pubGet did not fail'); throw AssertionError('pubGet did not fail');
} on ToolExit catch (error) { } on ToolExit catch (error) {
expect(error.message, 'pub get failed (66; err3)'); expect(error.message, 'pub get failed (66; err3)');
} }
expect(testLogger.statusText, expect(logger.statusText,
'Running "flutter pub get" in /...\n' 'Running "flutter pub get" in /...\n'
'out1\n' 'out1\n'
'out2\n' 'out2\n'
'out3\n' 'out3\n'
); );
expect(testLogger.errorText, expect(logger.errorText,
'err1\n' 'err1\n'
'err2\n' 'err2\n'
'err3\n' 'err3\n'
); );
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
FileSystem: () => MockFileSystem(),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{}),
),
Pub: () => const Pub(),
}); });
testUsingContext('pub cache in root is used', () async { testWithoutContext('pub cache in root is used', () async {
String error; String error;
final MockProcessManager processMock = MockProcessManager(69);
final MockProcessManager processMock = context.get<ProcessManager>() as MockProcessManager; final MockFileSystem fsMock = MockFileSystem();
final MockFileSystem fsMock = context.get<FileSystem>() as MockFileSystem; final Pub pub = Pub(
platform: FakePlatform(environment: const <String, String>{}),
usage: MockUsage(),
fileSystem: fsMock,
logger: BufferLogger.test(),
processManager: processMock,
botDetector: const BotDetectorAlwaysNo(),
);
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
MockDirectory.findCache = true; MockDirectory.findCache = true;
...@@ -148,124 +158,137 @@ void main() { ...@@ -148,124 +158,137 @@ void main() {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
}); });
time.elapse(const Duration(milliseconds: 500)); time.elapse(const Duration(milliseconds: 500));
expect(processMock.lastPubCache, equals(fsMock.path.join(Cache.flutterRoot, '.pub-cache'))); expect(processMock.lastPubCache, equals(fsMock.path.join(Cache.flutterRoot, '.pub-cache')));
expect(error, isNull); expect(error, isNull);
}); });
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(69),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{}),
),
Pub: () => const Pub(),
}); });
testUsingContext('pub cache in environment is used', () async { testWithoutContext('pub cache in environment is used', () async {
String error; final MockProcessManager processMock = MockProcessManager(69);
final Pub pub = Pub(
final MockProcessManager processMock = context.get<ProcessManager>() as MockProcessManager; fileSystem: MockFileSystem(),
logger: BufferLogger.test(),
processManager: processMock,
usage: MockUsage(),
botDetector: const BotDetectorAlwaysNo(),
platform: FakePlatform(
environment: const <String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
},
),
);
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
MockDirectory.findCache = true; MockDirectory.findCache = true;
expect(processMock.lastPubEnvironment, isNull); expect(processMock.lastPubEnvironment, isNull);
expect(processMock.lastPubCache, isNull); expect(processMock.lastPubCache, isNull);
String error;
pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) { pub.get(context: PubContext.flutterTests, checkLastModified: false).then((void value) {
error = 'test completed unexpectedly'; error = 'test completed unexpectedly';
}, onError: (dynamic thrownError) { }, onError: (dynamic thrownError) {
error = 'test failed unexpectedly: $thrownError'; error = 'test failed unexpectedly: $thrownError';
}); });
time.elapse(const Duration(milliseconds: 500)); time.elapse(const Duration(milliseconds: 500));
expect(processMock.lastPubCache, equals('custom/pub-cache/path')); expect(processMock.lastPubCache, equals('custom/pub-cache/path'));
expect(error, isNull); expect(error, isNull);
}); });
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(69),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
}),
),
Pub: () => const Pub(),
}); });
testUsingContext('analytics sent on success', () async { testWithoutContext('analytics sent on success', () async {
MockDirectory.findCache = true; MockDirectory.findCache = true;
final MockUsage usage = MockUsage();
final Pub pub = Pub(
fileSystem: MockFileSystem(),
logger: BufferLogger.test(),
processManager: MockProcessManager(0),
botDetector: const BotDetectorAlwaysNo(),
usage: usage,
platform: FakePlatform(
environment: const <String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
}
),
);
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
}, overrides: <Type, Generator>{ verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(0),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
}),
),
Usage: () => MockUsage(),
Pub: () => const Pub(),
}); });
testUsingContext('analytics sent on failure', () async { testWithoutContext('analytics sent on failure', () async {
MockDirectory.findCache = true; MockDirectory.findCache = true;
final MockUsage usage = MockUsage();
final Pub pub = Pub(
usage: usage,
fileSystem: MockFileSystem(),
logger: BufferLogger.test(),
processManager: MockProcessManager(1),
botDetector: const BotDetectorAlwaysNo(),
platform: FakePlatform(
environment: const <String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
},
),
);
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
}, overrides: <Type, Generator>{ verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(1),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
}),
),
Usage: () => MockUsage(),
Pub: () => const Pub(),
}); });
testUsingContext('analytics sent on failed version solve', () async { testWithoutContext('analytics sent on failed version solve', () async {
MockDirectory.findCache = true; MockDirectory.findCache = true;
final MockUsage usage = MockUsage();
final Pub pub = Pub(
fileSystem: MockFileSystem(),
logger: BufferLogger.test(),
processManager: MockProcessManager(
1,
stderr: 'version solving failed',
),
platform: FakePlatform(
environment: <String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
},
),
usage: usage,
botDetector: const BotDetectorAlwaysNo(),
);
try { try {
await pub.get(context: PubContext.flutterTests, checkLastModified: false); await pub.get(context: PubContext.flutterTests, checkLastModified: false);
} on ToolExit { } on ToolExit {
// Ignore. // Ignore.
} }
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
}, overrides: <Type, Generator>{ verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(
1,
stderr: 'version solving failed',
),
Platform: () => FakePlatform(
environment: UnmodifiableMapView<String, String>(<String, String>{
'PUB_CACHE': 'custom/pub-cache/path',
}),
),
Usage: () => MockUsage(),
Pub: () => const Pub(),
}); });
test('Pub error handling', () async { testWithoutContext('Pub error handling', () async {
final MemoryFileSystem fileSystem = MemoryFileSystem(); final BufferLogger logger = BufferLogger.test();
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand( FakeCommand(
command: const <String>[ command: const <String>[
'/bin/cache/dart-sdk/bin/pub', 'bin/cache/dart-sdk/bin/pub',
'--verbosity=warning', '--verbosity=warning',
'get', 'get',
'--no-precompile', '--no-precompile',
], ],
onRun: () { onRun: () {
globals.fs.file('.packages') fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2002)); .setLastModifiedSync(DateTime(2002));
} }
), ),
const FakeCommand( const FakeCommand(
command: <String>[ command: <String>[
'/bin/cache/dart-sdk/bin/pub', 'bin/cache/dart-sdk/bin/pub',
'--verbosity=warning', '--verbosity=warning',
'get', 'get',
'--no-precompile', '--no-precompile',
...@@ -273,96 +296,105 @@ void main() { ...@@ -273,96 +296,105 @@ void main() {
), ),
FakeCommand( FakeCommand(
command: const <String>[ command: const <String>[
'/bin/cache/dart-sdk/bin/pub', 'bin/cache/dart-sdk/bin/pub',
'--verbosity=warning', '--verbosity=warning',
'get', 'get',
'--no-precompile', '--no-precompile',
], ],
onRun: () { onRun: () {
globals.fs.file('pubspec.yaml') fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2002)); .setLastModifiedSync(DateTime(2002));
} }
), ),
const FakeCommand( const FakeCommand(
command: <String>[ command: <String>[
'/bin/cache/dart-sdk/bin/pub', 'bin/cache/dart-sdk/bin/pub',
'--verbosity=warning', '--verbosity=warning',
'get', 'get',
'--no-precompile', '--no-precompile',
], ],
), ),
]); ]);
await Testbed().run(() async { final Pub pub = Pub(
// the good scenario: .packages is old, pub updates the file. usage: MockUsage(),
globals.fs.file('.packages') fileSystem: fileSystem,
..createSync() logger: logger,
..setLastModifiedSync(DateTime(2000)); processManager: processManager,
globals.fs.file('pubspec.yaml') platform: FakePlatform(
..createSync()
..setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub sets date of .packages to 2002
expect(testLogger.statusText, 'Running "flutter pub get" in /...\n');
expect(testLogger.errorText, isEmpty);
expect(globals.fs.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it
expect(globals.fs.file('.packages').lastModifiedSync(), isNot(DateTime(2000))); // because pub changes it to 2002
expect(globals.fs.file('.packages').lastModifiedSync(), isNot(DateTime(2002))); // because we set the timestamp again after pub
testLogger.clear();
// bad scenario 1: pub doesn't update file; doesn't matter, because we do instead
globals.fs.file('.packages')
.setLastModifiedSync(DateTime(2000));
globals.fs.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing
expect(testLogger.statusText, 'Running "flutter pub get" in /...\n');
expect(testLogger.errorText, isEmpty);
expect(globals.fs.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it
expect(globals.fs.file('.packages').lastModifiedSync(), isNot(DateTime(2000))); // because we set the timestamp
expect(globals.fs.file('.packages').lastModifiedSync(), isNot(DateTime(2002))); // just in case FakeProcessManager is buggy
testLogger.clear();
// bad scenario 2: pub changes pubspec.yaml instead
globals.fs.file('.packages')
.setLastModifiedSync(DateTime(2000));
globals.fs.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001));
try {
await pub.get(context: PubContext.flutterTests, checkLastModified: true);
expect(true, isFalse, reason: 'pub.get did not throw');
} on ToolExit catch (error) {
expect(error.message, '/: unexpected concurrent modification of pubspec.yaml while running pub.');
}
expect(testLogger.statusText, 'Running "flutter pub get" in /...\n');
expect(testLogger.errorText, isEmpty);
expect(globals.fs.file('pubspec.yaml').lastModifiedSync(), DateTime(2002)); // because fake pub above touched it
expect(globals.fs.file('.packages').lastModifiedSync(), DateTime(2000)); // because nothing touched it
// bad scenario 3: pubspec.yaml was created in the future
globals.fs.file('.packages')
.setLastModifiedSync(DateTime(2000));
globals.fs.file('pubspec.yaml')
.setLastModifiedSync(DateTime(9999));
assert(DateTime(9999).isAfter(DateTime.now()));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing
expect(testLogger.statusText, contains('Running "flutter pub get" in /...\n'));
expect(testLogger.errorText, startsWith(
'Warning: File "/pubspec.yaml" was created in the future. Optimizations that rely on '
'comparing time stamps will be unreliable. Check your system clock for accuracy.\n'
'The timestamp was:'
));
testLogger.clear();
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Pub: () => const Pub(),
Platform: () => FakePlatform(
operatingSystem: 'linux', // so that the command executed is consistent operatingSystem: 'linux', // so that the command executed is consistent
environment: <String, String>{}, environment: <String, String>{},
), ),
BotDetector: () => const BotDetectorAlwaysNo(), // so that the test never adds --trace to the pub command botDetector: const BotDetectorAlwaysNo()
}); );
// the good scenario: .packages is old, pub updates the file.
fileSystem.file('.dart_tool/package_config.json')
..createSync(recursive: true)
..setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
..createSync()
..setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub sets date of .packages to 2002
expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty);
expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it
expect(fileSystem.file('.dart_tool/package_config.json').lastModifiedSync(), isNot(DateTime(2000))); // because pub changes it to 2002
expect(fileSystem.file('.dart_tool/package_config.json').lastModifiedSync(), isNot(DateTime(2002))); // because we set the timestamp again after pub
logger.clear();
// bad scenario 1: pub doesn't update file; doesn't matter, because we do instead
fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing
expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty);
expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2001)); // because nothing should touch it
expect(fileSystem.file('.dart_tool/package_config.json').lastModifiedSync(), isNot(DateTime(2000))); // because we set the timestamp
expect(fileSystem.file('.dart_tool/package_config.json').lastModifiedSync(), isNot(DateTime(2002))); // just in case FakeProcessManager is buggy
logger.clear();
// bad scenario 2: pub changes pubspec.yaml instead
fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(2001));
try {
await pub.get(context: PubContext.flutterTests, checkLastModified: true);
expect(true, isFalse, reason: 'pub.get did not throw');
} on ToolExit catch (error) {
expect(error.message, '/: unexpected concurrent modification of pubspec.yaml while running pub.');
}
expect(logger.statusText, 'Running "flutter pub get" in /...\n');
expect(logger.errorText, isEmpty);
expect(fileSystem.file('pubspec.yaml').lastModifiedSync(), DateTime(2002)); // because fake pub above touched it
expect(fileSystem.file('.dart_tool/package_config.json').lastModifiedSync(), DateTime(2000)); // because nothing touched it
// bad scenario 3: pubspec.yaml was created in the future
fileSystem.file('.dart_tool/package_config.json')
.setLastModifiedSync(DateTime(2000));
fileSystem.file('pubspec.yaml')
.setLastModifiedSync(DateTime(9999));
assert(DateTime(9999).isAfter(DateTime.now()));
await pub.get(context: PubContext.flutterTests, checkLastModified: true); // pub does nothing
expect(logger.statusText, contains('Running "flutter pub get" in /...\n'));
expect(logger.errorText, startsWith(
'Warning: File "/pubspec.yaml" was created in the future. Optimizations that rely on '
'comparing time stamps will be unreliable. Check your system clock for accuracy.\n'
'The timestamp was:'
));
logger.clear();
}); });
} }
class BotDetectorAlwaysNo implements BotDetector { class BotDetectorAlwaysNo implements BotDetector {
const BotDetectorAlwaysNo(); const BotDetectorAlwaysNo();
@override @override
Future<bool> get isRunningOnBot async => false; Future<bool> get isRunningOnBot async => false;
} }
...@@ -405,7 +437,7 @@ class MockProcessManager implements ProcessManager { ...@@ -405,7 +437,7 @@ class MockProcessManager implements ProcessManager {
} }
class MockFileSystem extends ForwardingFileSystem { class MockFileSystem extends ForwardingFileSystem {
MockFileSystem() : super(MemoryFileSystem()); MockFileSystem() : super(MemoryFileSystem.test());
@override @override
File file(dynamic path) { File file(dynamic path) {
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/dart/pub.dart';
import 'package:meta/meta.dart';
class ThrowingPub implements Pub { class ThrowingPub implements Pub {
@override @override
...@@ -34,7 +36,7 @@ class ThrowingPub implements Pub { ...@@ -34,7 +36,7 @@ class ThrowingPub implements Pub {
} }
@override @override
Future<void> interactively(List<String> arguments, {String directory}) { Future<void> interactively(List<String> arguments, {String directory, @required Stdio stdio,}) {
throw UnsupportedError('Attempted to invoke pub during test.'); throw UnsupportedError('Attempted to invoke pub during test.');
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment