Warm cache with all transitive dependencies in `flutter update-packages` command (#96258)
diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart
index defc86c..2f5e9ed 100644
--- a/packages/flutter_tools/lib/src/cache.dart
+++ b/packages/flutter_tools/lib/src/cache.dart
@@ -153,7 +153,7 @@
platform ??= FakePlatform(environment: <String, String>{});
logger ??= BufferLogger.test();
return Cache(
- rootOverride: rootOverride ??= fileSystem.directory('cache'),
+ rootOverride: rootOverride ?? fileSystem.directory('cache'),
artifacts: artifacts ?? <ArtifactSet>[],
logger: logger,
fileSystem: fileSystem,
diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart
index c293a11..6c54eff 100644
--- a/packages/flutter_tools/lib/src/commands/update_packages.dart
+++ b/packages/flutter_tools/lib/src/commands/update_packages.dart
@@ -97,6 +97,12 @@
help: 'For Flutter CLI testing only, forces this command to throw an unhandled exception.',
defaultsTo: false,
negatable: false,
+ )
+ ..addOption(
+ 'jobs',
+ abbr: 'j',
+ help: 'Causes the "pub get" runs to happen concurrently on this many '
+ 'CPUs. Defaults to the number of CPUs that this machine has.',
);
}
@@ -141,19 +147,19 @@
Future<FlutterCommandResult> runCommand() async {
final List<Directory> packages = runner.getRepoPackages();
- final bool upgrade = boolArg('force-upgrade');
+ final bool forceUpgrade = boolArg('force-upgrade');
final bool isPrintPaths = boolArg('paths');
final bool isPrintTransitiveClosure = boolArg('transitive-closure');
final bool isVerifyOnly = boolArg('verify-only');
final bool isConsumerOnly = boolArg('consumer-only');
final bool offline = boolArg('offline');
- final bool crash = boolArg('crash');
+ final bool doUpgrade = forceUpgrade || isPrintPaths || isPrintTransitiveClosure;
- if (crash) {
+ if (boolArg('crash')) {
throw StateError('test crash please ignore.');
}
- if (upgrade && offline) {
+ if (forceUpgrade && offline) {
throwToolExit(
'--force-upgrade cannot be used with the --offline flag'
);
@@ -177,60 +183,10 @@
}
if (isVerifyOnly) {
- bool needsUpdate = false;
- globals.printStatus('Verifying pubspecs...');
- for (final Directory directory in packages) {
- PubspecYaml pubspec;
- try {
- pubspec = PubspecYaml(directory);
- } on String catch (message) {
- throwToolExit(message);
- }
- globals.printTrace('Reading pubspec.yaml from ${directory.path}');
- if (pubspec.checksum.value == null) {
- // If the checksum is invalid or missing, we can just ask them run to run
- // upgrade again to compute it.
- globals.printWarning(
- 'Warning: pubspec in ${directory.path} has out of date dependencies. '
- 'Please run "flutter update-packages --force-upgrade" to update them correctly.'
- );
- needsUpdate = true;
- }
- // all dependencies in the pubspec sorted lexically.
- final Map<String, String> checksumDependencies = <String, String>{};
- for (final PubspecLine data in pubspec.inputData) {
- if (data is PubspecDependency && data.kind == DependencyKind.normal) {
- checksumDependencies[data.name] = data.version;
- }
- }
- final String checksum = _computeChecksum(checksumDependencies.keys, (String name) => checksumDependencies[name]);
- if (checksum != pubspec.checksum.value) {
- // If the checksum doesn't match, they may have added or removed some dependencies.
- // we need to run update-packages to recapture the transitive deps.
- globals.printWarning(
- 'Warning: pubspec in ${directory.path} has updated or new dependencies. '
- 'Please run "flutter update-packages --force-upgrade" to update them correctly '
- '(checksum ${pubspec.checksum.value} != $checksum).'
- );
- needsUpdate = true;
- } else {
- // everything is correct in the pubspec.
- globals.printTrace('pubspec in ${directory.path} is up to date!');
- }
- }
- if (needsUpdate) {
- throwToolExit(
- 'Warning: one or more pubspecs have invalid dependencies. '
- 'Please run "flutter update-packages --force-upgrade" to update them correctly.',
- exitCode: 1,
- );
- }
- globals.printStatus('All pubspecs were up to date.');
+ _verifyPubspecs(packages);
return FlutterCommandResult.success();
}
- final Map<String, PubspecDependency> dependencies = <String, PubspecDependency>{};
- final bool doUpgrade = upgrade || isPrintPaths || isPrintTransitiveClosure;
if (doUpgrade) {
// This feature attempts to collect all the packages used across all the
// pubspec.yamls in the repo (including via transitive dependencies), and
@@ -239,9 +195,116 @@
globals.printStatus('Upgrading packages...');
}
- // First, collect up the explicit dependencies:
+ // First, collect the dependencies:
final List<PubspecYaml> pubspecs = <PubspecYaml>[];
+ final Map<String, PubspecDependency> explicitDependencies = <String, PubspecDependency>{};
+ final Map<String, PubspecDependency> allDependencies = <String, PubspecDependency>{};
final Set<String> specialDependencies = <String>{};
+ _collectDependencies(
+ packages: packages,
+ pubspecs: pubspecs,
+ explicitDependencies: explicitDependencies,
+ allDependencies: allDependencies,
+ specialDependencies: specialDependencies,
+ doUpgrade: doUpgrade,
+ );
+
+ // Now that we have all the dependencies we care about, we are going to
+ // create a fake package and then run either "pub upgrade", if requested,
+ // followed by "pub get" on it. If upgrading, the pub tool will attempt to
+ // bring these dependencies up to the most recent possible versions while
+ // honoring all their constraints. If not upgrading the pub tool will only
+ // attempt to download any necessary package versions to the pub cache to
+ // warm the cache.
+ final PubDependencyTree tree = PubDependencyTree(); // object to collect results
+ final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.');
+ await _generateFakePackage(
+ tempDir: tempDir,
+ dependencies: doUpgrade ? explicitDependencies.values : allDependencies.values,
+ pubspecs: pubspecs,
+ tree: tree,
+ doUpgrade: doUpgrade,
+ );
+
+ if (doUpgrade) {
+ final bool done = _upgradePubspecs(
+ tree: tree,
+ pubspecs: pubspecs,
+ explicitDependencies: explicitDependencies,
+ specialDependencies: specialDependencies,
+ );
+
+ if (done) {
+ // Complete early if we were just printing data.
+ return FlutterCommandResult.success();
+ }
+ }
+
+ await _runPubGetOnPackages(packages);
+
+ return FlutterCommandResult.success();
+ }
+
+ void _verifyPubspecs(List<Directory> packages) {
+ bool needsUpdate = false;
+ globals.printStatus('Verifying pubspecs...');
+ for (final Directory directory in packages) {
+ PubspecYaml pubspec;
+ try {
+ pubspec = PubspecYaml(directory);
+ } on String catch (message) {
+ throwToolExit(message);
+ }
+ globals.printTrace('Reading pubspec.yaml from ${directory.path}');
+ if (pubspec.checksum.value == null) {
+ // If the checksum is invalid or missing, we can just ask them run to run
+ // upgrade again to compute it.
+ globals.printWarning(
+ 'Warning: pubspec in ${directory.path} has out of date dependencies. '
+ 'Please run "flutter update-packages --force-upgrade" to update them correctly.'
+ );
+ needsUpdate = true;
+ }
+ // all dependencies in the pubspec sorted lexically.
+ final Map<String, String> checksumDependencies = <String, String>{};
+ for (final PubspecLine data in pubspec.inputData) {
+ if (data is PubspecDependency && data.kind == DependencyKind.normal) {
+ checksumDependencies[data.name] = data.version;
+ }
+ }
+ final String checksum = _computeChecksum(checksumDependencies.keys, (String name) => checksumDependencies[name]);
+ if (checksum != pubspec.checksum.value) {
+ // If the checksum doesn't match, they may have added or removed some dependencies.
+ // we need to run update-packages to recapture the transitive deps.
+ globals.printWarning(
+ 'Warning: pubspec in ${directory.path} has updated or new dependencies. '
+ 'Please run "flutter update-packages --force-upgrade" to update them correctly '
+ '(checksum ${pubspec.checksum.value} != $checksum).'
+ );
+ needsUpdate = true;
+ } else {
+ // everything is correct in the pubspec.
+ globals.printTrace('pubspec in ${directory.path} is up to date!');
+ }
+ }
+ if (needsUpdate) {
+ throwToolExit(
+ 'Warning: one or more pubspecs have invalid dependencies. '
+ 'Please run "flutter update-packages --force-upgrade" to update them correctly.',
+ exitCode: 1,
+ );
+ }
+ globals.printStatus('All pubspecs were up to date.');
+ }
+
+ void _collectDependencies({
+ @required List<Directory> packages,
+ @required List<PubspecYaml> pubspecs,
+ @required Set<String> specialDependencies,
+ @required Map<String, PubspecDependency> explicitDependencies,
+ @required Map<String, PubspecDependency> allDependencies,
+ @required bool doUpgrade,
+ }) {
// Visit all the directories with pubspec.yamls we care about.
for (final Directory directory in packages) {
if (doUpgrade) {
@@ -254,8 +317,8 @@
throwToolExit(message);
}
pubspecs.add(pubspec); // remember it for later
- for (final PubspecDependency dependency in pubspec.allDependencies) { // this is all the explicit dependencies
- if (dependencies.containsKey(dependency.name)) {
+ for (final PubspecDependency dependency in pubspec.allDependencies) {
+ if (allDependencies.containsKey(dependency.name)) {
// If we've seen the dependency before, make sure that we are
// importing it the same way. There's several ways to import a
// dependency. Hosted (from pub via version number), by path (e.g.
@@ -266,17 +329,47 @@
// This makes sure that we don't import a package in two different
// ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and
// saying "path: ../../..." in another.
- final PubspecDependency previous = dependencies[dependency.name];
+ final PubspecDependency previous = allDependencies[dependency.name];
if (dependency.kind != previous.kind || dependency.lockTarget != previous.lockTarget) {
throwToolExit(
- 'Inconsistent requirements around ${dependency.name}; '
- 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" '
- 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".'
+ 'Inconsistent requirements around ${dependency.name}; '
+ 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" '
+ 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".'
+ );
+ }
+ if (dependency.version != previous.version) {
+ globals.printError(
+ 'Requiring multiple versions: multiple versions required by ${dependency.name}; '
+ 'saw ${dependency.version} in "${dependency.sourcePath}" '
+ 'and ${previous.version} in "${previous.sourcePath}".'
+ );
+ }
+ }
+ allDependencies[dependency.name] = dependency;
+ }
+ for (final PubspecDependency dependency in pubspec.allExplicitDependencies) {
+ if (explicitDependencies.containsKey(dependency.name)) {
+ // If we've seen the dependency before, make sure that we are
+ // importing it the same way. There's several ways to import a
+ // dependency. Hosted (from pub via version number), by path (e.g.
+ // pointing at the version of a package we get from the Dart SDK
+ // that we download with Flutter), by SDK (e.g. the "flutter"
+ // package is explicitly from "sdk: flutter").
+ //
+ // This makes sure that we don't import a package in two different
+ // ways, e.g. by saying "sdk: flutter" in one pubspec.yaml and
+ // saying "path: ../../..." in another.
+ final PubspecDependency previous = explicitDependencies[dependency.name];
+ if (dependency.kind != previous.kind || dependency.lockTarget != previous.lockTarget) {
+ throwToolExit(
+ 'Inconsistent requirements around ${dependency.name}; '
+ 'saw ${dependency.kind} (${dependency.lockTarget}) in "${dependency.sourcePath}" '
+ 'and ${previous.kind} (${previous.lockTarget}) in "${previous.sourcePath}".'
);
}
}
// Remember this dependency by name so we can look it up again.
- dependencies[dependency.name] = dependency;
+ explicitDependencies[dependency.name] = dependency;
// Normal dependencies are those we get from pub. The others we
// already implicitly pin since we pull down one version of the
// Flutter and Dart SDKs, so we track which those are here so that we
@@ -286,29 +379,28 @@
}
}
}
+ }
- // Now that we have all the dependencies we explicitly care about, we are
- // going to create a fake package and then run either "pub upgrade" or "pub
- // get" on it, depending on whether we are upgrading or not. If upgrading,
- // the pub tool will attempt to bring these dependencies up to the most
- // recent possible versions while honoring all their constraints. If not
- // upgrading the pub tool will attempt to download any necessary package
- // versions to the pub cache to warm the cache.
- final PubDependencyTree tree = PubDependencyTree(); // object to collect results
- final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.');
+ Future<void> _generateFakePackage({
+ Directory tempDir,
+ Iterable<PubspecDependency> dependencies,
+ List<PubspecYaml> pubspecs,
+ PubDependencyTree tree,
+ bool doUpgrade,
+ }) async {
try {
final File fakePackage = _pubspecFor(tempDir);
fakePackage.createSync();
fakePackage.writeAsStringSync(
_generateFakePubspec(
- dependencies.values,
+ dependencies,
useAnyVersion: doUpgrade,
),
);
// Create a synthetic flutter SDK so that transitive flutter SDK
// constraints are not affected by this upgrade.
Directory temporaryFlutterSdk;
- if (upgrade) {
+ if (doUpgrade) {
temporaryFlutterSdk = createTemporaryFlutterSdk(
globals.logger,
globals.fs,
@@ -317,17 +409,14 @@
);
}
- // Next we run "pub upgrade" on this generated package, if we're doing
- // an upgrade. Otherwise, we just run a regular "pub get" on it in order
- // to force the download of any needed packages to the pub cache.
+ // Next we run "pub get" on it in order to force the download of any
+ // needed packages to the pub cache, upgrading if requested.
await pub.get(
context: PubContext.updatePackages,
directory: tempDir.path,
upgrade: doUpgrade,
- offline: offline,
- flutterRootOverride: upgrade
- ? temporaryFlutterSdk.path
- : null,
+ offline: boolArg('offline'),
+ flutterRootOverride: doUpgrade ? temporaryFlutterSdk.path : null,
generateSyntheticPackage: false,
);
// Cleanup the temporary SDK
@@ -354,54 +443,57 @@
} finally {
tempDir.deleteSync(recursive: true);
}
+ }
- if (doUpgrade) {
- // The transitive dependency tree for the fake package does not contain
- // dependencies between Flutter SDK packages and pub packages. We add them
- // here.
- for (final PubspecYaml pubspec in pubspecs) {
- final String package = pubspec.name;
- specialDependencies.add(package);
- tree._versions[package] = pubspec.version;
- assert(!tree._dependencyTree.containsKey(package));
- tree._dependencyTree[package] = <String>{};
- for (final PubspecDependency dependency in pubspec.dependencies) {
- if (dependency.kind == DependencyKind.normal) {
- tree._dependencyTree[package].add(dependency.name);
- }
+ bool _upgradePubspecs({
+ @required PubDependencyTree tree,
+ @required List<PubspecYaml> pubspecs,
+ @required Set<String> specialDependencies,
+ @required Map<String, PubspecDependency> explicitDependencies,
+ }) {
+ // The transitive dependency tree for the fake package does not contain
+ // dependencies between Flutter SDK packages and pub packages. We add them
+ // here.
+ for (final PubspecYaml pubspec in pubspecs) {
+ final String package = pubspec.name;
+ specialDependencies.add(package);
+ tree._versions[package] = pubspec.version;
+ assert(!tree._dependencyTree.containsKey(package));
+ tree._dependencyTree[package] = <String>{};
+ for (final PubspecDependency dependency in pubspec.dependencies) {
+ if (dependency.kind == DependencyKind.normal) {
+ tree._dependencyTree[package].add(dependency.name);
}
}
-
- if (isPrintTransitiveClosure) {
- tree._dependencyTree.forEach((String from, Set<String> to) {
- globals.printStatus('$from -> $to');
- });
- return FlutterCommandResult.success();
- }
-
- if (isPrintPaths) {
- showDependencyPaths(from: stringArg('from'), to: stringArg('to'), tree: tree);
- return FlutterCommandResult.success();
- }
-
- // Now that we have collected all the data, we can apply our dependency
- // versions to each pubspec.yaml that we collected. This mutates the
- // pubspec.yaml files.
- //
- // The specialDependencies argument is the set of package names to not pin
- // to specific versions because they are explicitly pinned by their
- // constraints. Here we list the names we earlier established we didn't
- // need to pin because they come from the Dart or Flutter SDKs.
- for (final PubspecYaml pubspec in pubspecs) {
- pubspec.apply(tree, specialDependencies);
- }
-
- // Now that the pubspec.yamls are updated, we run "pub get" on each one so
- // that the various packages are ready to use. This is what "flutter
- // update-packages" does without --force-upgrade, so we can just fall into
- // the regular code path.
}
+ if (boolArg('transitive-closure')) {
+ tree._dependencyTree.forEach((String from, Set<String> to) {
+ globals.printStatus('$from -> $to');
+ });
+ return true;
+ }
+
+ if (boolArg('paths')) {
+ showDependencyPaths(from: stringArg('from'), to: stringArg('to'), tree: tree);
+ return true;
+ }
+
+ // Now that we have collected all the data, we can apply our dependency
+ // versions to each pubspec.yaml that we collected. This mutates the
+ // pubspec.yaml files.
+ //
+ // The specialDependencies argument is the set of package names to not pin
+ // to specific versions because they are explicitly pinned by their
+ // constraints. Here we list the names we earlier established we didn't
+ // need to pin because they come from the Dart or Flutter SDKs.
+ for (final PubspecYaml pubspec in pubspecs) {
+ pubspec.apply(tree, specialDependencies);
+ }
+ return false;
+ }
+
+ Future<void> _runPubGetOnPackages(List<Directory> packages) async {
final Stopwatch timer = Stopwatch()..start();
int count = 0;
@@ -416,7 +508,7 @@
'Running "flutter pub get" in affected packages...',
);
try {
- final TaskQueue<void> queue = TaskQueue<void>();
+ final TaskQueue<void> queue = TaskQueue<void>(maxJobs: intArg('jobs'));
for (final Directory dir in packages) {
unawaited(queue.add(() async {
final Stopwatch stopwatch = Stopwatch();
@@ -424,7 +516,9 @@
await pub.get(
context: PubContext.updatePackages,
directory: dir.path,
- offline: offline,
+ // All dependencies should already have been downloaded by the fake
+ // package, so the concurrent checks can all happen offline.
+ offline: true,
generateSyntheticPackage: false,
printProgress: false,
);
@@ -452,8 +546,6 @@
final double seconds = timer.elapsedMilliseconds / 1000.0;
globals.printStatus("\nRan 'pub get' $count time${count == 1 ? "" : "s"} and fetched coverage data in ${seconds.toStringAsFixed(1)}s.");
-
- return FlutterCommandResult.success();
}
void showDependencyPaths({
@@ -752,12 +844,17 @@
}
/// This returns all regular dependencies and all dev dependencies.
- Iterable<PubspecDependency> get allDependencies {
+ Iterable<PubspecDependency> get allExplicitDependencies {
return inputData
.whereType<PubspecDependency>()
.where((PubspecDependency data) => data.kind != DependencyKind.overridden && !data.isTransitive);
}
+ /// This returns all dependencies.
+ Iterable<PubspecDependency> get allDependencies {
+ return inputData.whereType<PubspecDependency>();
+ }
+
/// Take a dependency graph with explicit version numbers, and apply them to
/// the pubspec.yaml, ignoring any that we know are special dependencies (those
/// that depend on the Flutter or Dart SDK directly and are thus automatically
@@ -814,7 +911,8 @@
// We output data that matches the format that
// PubspecDependency.parse can handle. The data.suffix is any
// previously-specified trailing comment.
- assert(versions.contains(data.name));
+ assert(versions.contains(data.name),
+ "versions doesn't contain ${data.name}");
output.add(' ${data.name}: ${versions.versionFor(data.name)}${data.suffix}');
} else {
// If it wasn't a regular dependency, then we output the line
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 96bff4a..6a69357 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -1473,12 +1473,15 @@
ApplicationPackageFactory? applicationPackages;
- /// Gets the parsed command-line option named [name] as `bool`.
+ /// Gets the parsed command-line option named [name] as a `bool`.
bool boolArg(String name) => argResults?[name] as bool? ?? false;
- /// Gets the parsed command-line option named [name] as `String`.
+ /// Gets the parsed command-line option named [name] as a `String`.
String? stringArg(String name) => argResults?[name] as String?;
+ /// Gets the parsed command-line option named [name] as an `int`.
+ int? intArg(String name) => argResults?[name] as int?;
+
/// Gets the parsed command-line option named [name] as `List<String>`.
List<String> stringsArg(String name) => argResults?[name] as List<String>? ?? <String>[];
}
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart
index c8f2bc3..78018b4 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart
@@ -4,9 +4,75 @@
// @dart = 2.8
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:flutter_tools/src/base/file_system.dart';
+import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/update_packages.dart';
+import 'package:flutter_tools/src/dart/pub.dart';
+import 'package:meta/meta.dart';
+import 'package:test/fake.dart';
import '../../src/common.dart';
+import '../../src/context.dart';
+import '../../src/test_flutter_command_runner.dart';
+
+// An example pubspec.yaml from flutter, not necessary for it to be up to date.
+const String kFlutterPubspecYaml = r'''
+name: flutter
+description: A framework for writing Flutter applications
+homepage: http://flutter.dev
+
+environment:
+ sdk: ">=2.2.2 <3.0.0"
+
+dependencies:
+ # To update these, use "flutter update-packages --force-upgrade".
+ collection: 1.14.11
+ meta: 1.1.8
+ typed_data: 1.1.6
+ vector_math: 2.0.8
+
+ sky_engine:
+ sdk: flutter
+
+ gallery:
+ git:
+ url: https://github.com/flutter/gallery.git
+ ref: d00362e6bdd0f9b30bba337c358b9e4a6e4ca950
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+ flutter_goldens:
+ sdk: flutter
+
+ archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+# PUBSPEC CHECKSUM: 1234
+''';
+
+// An example pubspec.yaml, not necessary for it to be up to date.
+const String kExamplesPubspecYaml = r'''
+name: examples
+description: Examples for flutter
+homepage: http://flutter.dev
+
+version: 1.0.0
+
+environment:
+ sdk: ">=2.14.0-383.0.dev <3.0.0"
+ flutter: ">=2.5.0-6.0.pre.30 <3.0.0"
+
+dependencies:
+ cupertino_icons: 1.0.4
+ flutter:
+ sdk: flutter
+
+ archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+# PUBSPEC CHECKSUM: 6543
+''';
void main() {
testWithoutContext('kManuallyPinnedDependencies pins are actually pins', () {
@@ -16,4 +82,148 @@
reason: 'Version pins in kManuallyPinnedDependencies must be specific pins, not ranges.',
);
});
+
+ group('update-packages', () {
+ FileSystem fileSystem;
+ Directory flutterSdk;
+ Directory flutter;
+ FakePub pub;
+
+ setUpAll(() {
+ Cache.disableLocking();
+ });
+
+ setUp(() {
+ fileSystem = MemoryFileSystem.test();
+ flutterSdk = fileSystem.directory('flutter')..createSync();
+ flutterSdk.childFile('version').writeAsStringSync('1.2.3');
+ flutter = flutterSdk.childDirectory('packages').childDirectory('flutter')
+ ..createSync(recursive: true);
+ flutterSdk.childDirectory('dev').createSync(recursive: true);
+ flutterSdk.childDirectory('examples').childFile('pubspec.yaml')
+ ..createSync(recursive: true)
+ ..writeAsStringSync(kExamplesPubspecYaml);
+ flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml);
+ Cache.flutterRoot = flutterSdk.absolute.path;
+ pub = FakePub(fileSystem);
+ });
+
+ testUsingContext('updates packages', () async {
+ final UpdatePackagesCommand command = UpdatePackagesCommand();
+ await createTestCommandRunner(command).run(<String>['update-packages']);
+ expect(pub.pubGetDirectories, equals(<String>[
+ '/.tmp_rand0/flutter_update_packages.rand0',
+ '/flutter/examples',
+ '/flutter/packages/flutter',
+ ]));
+ expect(pub.pubBatchDirectories, isEmpty);
+ }, overrides: <Type, Generator>{
+ Pub: () => pub,
+ FileSystem: () => fileSystem,
+ ProcessManager: () => FakeProcessManager.any(),
+ Cache: () => Cache.test(
+ processManager: FakeProcessManager.any(),
+ ),
+ });
+
+ testUsingContext('force updates packages', () async {
+ final UpdatePackagesCommand command = UpdatePackagesCommand();
+ await createTestCommandRunner(command).run(<String>[
+ 'update-packages',
+ '--force-upgrade',
+ ]);
+ expect(pub.pubGetDirectories, equals(<String>[
+ '/.tmp_rand0/flutter_update_packages.rand0',
+ '/flutter/examples',
+ '/flutter/packages/flutter',
+ ]));
+ expect(pub.pubBatchDirectories, equals(<String>[
+ '/.tmp_rand0/flutter_update_packages.rand0',
+ ]));
+ }, overrides: <Type, Generator>{
+ Pub: () => pub,
+ FileSystem: () => fileSystem,
+ ProcessManager: () => FakeProcessManager.any(),
+ Cache: () => Cache.test(
+ processManager: FakeProcessManager.any(),
+ ),
+ });
+ });
+}
+
+class FakePub extends Fake implements Pub {
+ FakePub(this.fileSystem);
+
+ final FileSystem fileSystem;
+ final List<String> pubGetDirectories = <String>[];
+ final List<String> pubBatchDirectories = <String>[];
+
+ @override
+ Future<void> get({
+ @required PubContext context,
+ String directory,
+ bool skipIfAbsent = false,
+ bool upgrade = false,
+ bool offline = false,
+ bool generateSyntheticPackage = false,
+ String flutterRootOverride,
+ bool checkUpToDate = false,
+ bool shouldSkipThirdPartyGenerator = true,
+ bool printProgress = true,
+ }) async {
+ pubGetDirectories.add(directory);
+ fileSystem.directory(directory).childFile('pubspec.lock')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ async:
+ dependency: "direct dev"
+ description:
+ name: async
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.8.2"
+sdks:
+ dart: ">=2.14.0 <3.0.0"
+''');
+ fileSystem.currentDirectory
+ .childDirectory('.dart_tool')
+ .childFile('package_config.json')
+ ..createSync(recursive: true)
+ ..writeAsStringSync('{"configVersion":2,"packages":[]}');
+ }
+
+ @override
+ Future<void> batch(
+ List<String> arguments, {
+ @required PubContext context,
+ String directory,
+ MessageFilter filter,
+ String failureMessage = 'pub failed',
+ @required bool retry,
+ bool showTraceForErrors,
+ }) async {
+ pubBatchDirectories.add(directory);
+
+'''
+Dart SDK 2.16.0-144.0.dev
+Flutter SDK 2.9.0-1.0.pre.263
+flutter_api_samples 1.0.0
+
+dependencies:
+- cupertino_icons 1.0.4
+- collection 1.15.0
+- meta 1.7.0
+- typed_data 1.3.0 [collection]
+- vector_math 2.1.1
+
+dev dependencies:
+
+transitive dependencies:
+- platform 3.1.0
+- process 4.2.4 [file path platform]
+'''.split('\n').forEach(filter);
+ }
}
diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart
index 537786f..74e191c 100644
--- a/packages/flutter_tools/test/general.shard/update_packages_test.dart
+++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart
@@ -79,36 +79,36 @@
''';
void main() {
- testWithoutContext('createTemporaryFlutterSdk creates an unpinned flutter SDK', () {
- final FileSystem fileSystem = MemoryFileSystem.test();
+ FileSystem fileSystem;
+ Directory flutterSdk;
+ Directory flutter;
+ setUp(() {
+ fileSystem = MemoryFileSystem.test();
// Setup simplified Flutter SDK.
- final Directory flutterSdk = fileSystem.directory('flutter')
- ..createSync();
+ flutterSdk = fileSystem.directory('flutter')..createSync();
// Create version file
flutterSdk.childFile('version').writeAsStringSync('1.2.3');
// Create a pubspec file
- final Directory flutter = flutterSdk
- .childDirectory('packages')
- .childDirectory('flutter')
+ flutter = flutterSdk.childDirectory('packages').childDirectory('flutter')
..createSync(recursive: true);
- flutter
- .childFile('pubspec.yaml')
- .writeAsStringSync(kFlutterPubspecYaml);
+ flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml);
+ });
+ testWithoutContext(
+ 'createTemporaryFlutterSdk creates an unpinned flutter SDK', () {
// A stray extra package should not cause a crash.
final Directory extra = flutterSdk
- .childDirectory('packages')
- .childDirectory('extra')
+ .childDirectory('packages')
+ .childDirectory('extra')
..createSync(recursive: true);
- extra
- .childFile('pubspec.yaml')
- .writeAsStringSync(kExtraPubspecYaml);
+ extra.childFile('pubspec.yaml').writeAsStringSync(kExtraPubspecYaml);
// Create already parsed pubspecs.
final PubspecYaml flutterPubspec = PubspecYaml(flutter);
- final PubspecDependency gitDependency = flutterPubspec.dependencies.firstWhere((PubspecDependency dep) => dep.kind == DependencyKind.git);
+ final PubspecDependency gitDependency = flutterPubspec.dependencies
+ .firstWhere((PubspecDependency dep) => dep.kind == DependencyKind.git);
expect(
gitDependency.lockLine,
'''
@@ -152,25 +152,57 @@
});
testWithoutContext('Throws a StateError on a malformed git: reference', () {
- final FileSystem fileSystem = MemoryFileSystem.test();
-
- // Setup simplified Flutter SDK.
- final Directory flutterSdk = fileSystem.directory('flutter')
- ..createSync();
- // Create version file
- flutterSdk.childFile('version').writeAsStringSync('1.2.3');
- // Create a pubspec file
- final Directory flutter = flutterSdk
- .childDirectory('packages')
- .childDirectory('flutter')
- ..createSync(recursive: true);
- flutter
- .childFile('pubspec.yaml')
- .writeAsStringSync(kInvalidGitPubspec);
+ // Create an invalid pubspec file.
+ flutter.childFile('pubspec.yaml').writeAsStringSync(kInvalidGitPubspec);
expect(
() => PubspecYaml(flutter),
throwsStateError,
);
});
+
+ testWithoutContext('PubspecYaml Loads dependencies', () async {
+ final PubspecYaml pubspecYaml = PubspecYaml(flutter);
+ expect(
+ pubspecYaml.allDependencies
+ .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}')
+ .toSet(),
+ equals(<String>{
+ 'collection: 1.14.11',
+ 'meta: 1.1.8',
+ 'typed_data: 1.1.6',
+ 'vector_math: 2.0.8',
+ 'sky_engine: ',
+ 'gallery: ',
+ 'flutter_test: ',
+ 'flutter_goldens: ',
+ 'archive: 2.0.11',
+ }));
+ expect(
+ pubspecYaml.allExplicitDependencies
+ .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}')
+ .toSet(),
+ equals(<String>{
+ 'collection: 1.14.11',
+ 'meta: 1.1.8',
+ 'typed_data: 1.1.6',
+ 'vector_math: 2.0.8',
+ 'sky_engine: ',
+ 'gallery: ',
+ 'flutter_test: ',
+ 'flutter_goldens: '
+ }));
+ expect(
+ pubspecYaml.dependencies
+ .map<String>((PubspecDependency dependency) => '${dependency.name}: ${dependency.version}')
+ .toSet(),
+ equals(<String>{
+ 'collection: 1.14.11',
+ 'meta: 1.1.8',
+ 'typed_data: 1.1.6',
+ 'vector_math: 2.0.8',
+ 'sky_engine: ',
+ 'gallery: '
+ }));
+ });
}