Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 75 additions & 52 deletions packages/flutter_tools/lib/src/commands/update_packages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,25 @@ class UpdatePackagesCommand extends FlutterCommand {
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.',
)
..addOption(
'synthetic-package-path',
help: 'Write the synthetic monolithic pub package generated to do '
'version solving to a persistent path. By default, a temporary '
'directory that is deleted before the command exits. By '
'providing this path, a Flutter maintainer can inspect further '
'exactly how version solving was achieved.',
);
}

@override
final String name = 'update-packages';

@override
final String description = 'Update the packages inside the Flutter repo.';
final String description = 'Update the packages inside the Flutter repo. '
'This is intended for CI and repo maintainers. '
'Normal Flutter developers should not have to '
'use this command.';

@override
final List<String> aliases = <String>['upgrade-packages'];
Expand Down Expand Up @@ -144,6 +155,22 @@ class UpdatePackagesCommand extends FlutterCommand {
..writeAsBytesSync(data, flush: true);
}

late final Directory _syntheticPackageDir = (() {
final String? optionPath = stringArg('synthetic-package-path');
if (optionPath == null) {
return globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.');
}
final Directory syntheticPackageDir = globals.fs.directory(optionPath);
if (!syntheticPackageDir.existsSync()) {
syntheticPackageDir.createSync(recursive: true);
}
globals.printStatus(
'The synthetic package with all pub dependencies across the repo will '
'be written to ${syntheticPackageDir.absolute.path}.',
);
return syntheticPackageDir;
})();

@override
Future<FlutterCommandResult> runCommand() async {
final List<Directory> packages = runner!.getRepoPackages();
Expand Down Expand Up @@ -218,15 +245,19 @@ class UpdatePackagesCommand extends FlutterCommand {
// 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,
tempDir: _syntheticPackageDir,
dependencies: doUpgrade ? explicitDependencies.values : allDependencies.values,
pubspecs: pubspecs,
tree: tree,
doUpgrade: doUpgrade,
);

// Only delete the synthetic package if it was done in a temp directory
if (stringArg('synthetic-package-path') == null) {
_syntheticPackageDir.deleteSync(recursive: true);
}

if (doUpgrade) {
final bool done = _upgradePubspecs(
tree: tree,
Expand Down Expand Up @@ -380,57 +411,49 @@ class UpdatePackagesCommand extends FlutterCommand {
required bool doUpgrade,
}) async {
Directory? temporaryFlutterSdk;
try {
final File fakePackage = _pubspecFor(tempDir);
fakePackage.createSync();
fakePackage.writeAsStringSync(
generateFakePubspec(
dependencies,
doUpgrade: doUpgrade,
),
final Directory syntheticPackageDir = tempDir.childDirectory('synthetic_package');
final File fakePackage = _pubspecFor(syntheticPackageDir);
fakePackage.createSync(recursive: true);
fakePackage.writeAsStringSync(
generateFakePubspec(
dependencies,
doUpgrade: doUpgrade,
),
);
// Create a synthetic flutter SDK so that transitive flutter SDK
// constraints are not affected by this upgrade.
if (doUpgrade) {
temporaryFlutterSdk = createTemporaryFlutterSdk(
globals.logger,
globals.fs,
globals.fs.directory(Cache.flutterRoot),
pubspecs,
tempDir,
);
// Create a synthetic flutter SDK so that transitive flutter SDK
// constraints are not affected by this upgrade.
if (doUpgrade) {
temporaryFlutterSdk = createTemporaryFlutterSdk(
globals.logger,
globals.fs,
globals.fs.directory(Cache.flutterRoot),
pubspecs,
);
}
}

// 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(
// 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,
project: FlutterProject.fromDirectory(syntheticPackageDir),
upgrade: doUpgrade,
offline: boolArgDeprecated('offline'),
flutterRootOverride: temporaryFlutterSdk?.path,
);

if (doUpgrade) {
// If upgrading, we run "pub deps --style=compact" on the result. We
// pipe all the output to tree.fill(), which parses it so that it can
// create a graph of all the dependencies so that we can figure out the
// transitive dependencies later. It also remembers which version was
// selected for each package.
await pub.batch(
<String>['deps', '--style=compact'],
context: PubContext.updatePackages,
project: FlutterProject.fromDirectory(tempDir),
upgrade: doUpgrade,
offline: boolArgDeprecated('offline'),
flutterRootOverride: temporaryFlutterSdk?.path,
directory: syntheticPackageDir.path,
filter: tree.fill,
);

if (doUpgrade) {
// If upgrading, we run "pub deps --style=compact" on the result. We
// pipe all the output to tree.fill(), which parses it so that it can
// create a graph of all the dependencies so that we can figure out the
// transitive dependencies later. It also remembers which version was
// selected for each package.
await pub.batch(
<String>['deps', '--style=compact'],
context: PubContext.updatePackages,
directory: tempDir.path,
filter: tree.fill,
);
}
} finally {
// Cleanup the temporary SDK
try {
temporaryFlutterSdk?.deleteSync(recursive: true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we ever clean up/delete this in the new code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right after we return from this method, we delete the parent (assuming we weren't passed an explicit --synthetic-package-path, which means we want it to persist after the tool exits): https://github.com/flutter/flutter/pull/115665/files#diff-61e5e832b7178fde4befd707ba407f598be7966a1671db8dc1a607661f09cca2R258

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK I forgot it was a child of tempDir

} on FileSystemException {
// Failed to delete temporary SDK.
}
tempDir.deleteSync(recursive: true);
}
}

Expand Down Expand Up @@ -1577,6 +1600,7 @@ Directory createTemporaryFlutterSdk(
FileSystem fileSystem,
Directory realFlutter,
List<PubspecYaml> pubspecs,
Directory tempDir,
) {
final Set<String> currentPackages = <String>{};
for (final FileSystemEntity entity in realFlutter.childDirectory('packages').listSync()) {
Expand All @@ -1591,8 +1615,7 @@ Directory createTemporaryFlutterSdk(
pubspecsByName[pubspec.name] = pubspec;
}

final Directory directory = fileSystem.systemTempDirectory
.createTempSync('flutter_upgrade_sdk.')
final Directory directory = tempDir.childDirectory('flutter_upgrade_sdk')
..createSync();
// Fill in version info.
realFlutter.childFile('version')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ void main() {
late Directory flutterSdk;
late Directory flutter;
late FakePub pub;
late FakeProcessManager processManager;

setUpAll(() {
Cache.disableLocking();
Expand All @@ -105,23 +106,24 @@ void main() {
flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml);
Cache.flutterRoot = flutterSdk.absolute.path;
pub = FakePub(fileSystem);
processManager = FakeProcessManager.empty();
});

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',
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
'/flutter/examples',
'/flutter/packages/flutter',
]));
expect(pub.pubBatchDirectories, isEmpty);
}, overrides: <Type, Generator>{
Pub: () => pub,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
ProcessManager: () => processManager,
Cache: () => Cache.test(
processManager: FakeProcessManager.any(),
processManager: processManager,
),
});

Expand All @@ -132,19 +134,19 @@ void main() {
'--force-upgrade',
]);
expect(pub.pubGetDirectories, equals(<String>[
'/.tmp_rand0/flutter_update_packages.rand0',
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
'/flutter/examples',
'/flutter/packages/flutter',
]));
expect(pub.pubBatchDirectories, equals(<String>[
'/.tmp_rand0/flutter_update_packages.rand0',
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
]));
}, overrides: <Type, Generator>{
Pub: () => pub,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
ProcessManager: () => processManager,
Cache: () => Cache.test(
processManager: FakeProcessManager.any(),
processManager: processManager,
),
});

Expand All @@ -156,19 +158,44 @@ void main() {
'--jobs=1',
]);
expect(pub.pubGetDirectories, equals(<String>[
'/.tmp_rand0/flutter_update_packages.rand0',
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
'/flutter/examples',
'/flutter/packages/flutter',
]));
expect(pub.pubBatchDirectories, equals(<String>[
'/.tmp_rand0/flutter_update_packages.rand0',
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
]));
}, overrides: <Type, Generator>{
Pub: () => pub,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
ProcessManager: () => processManager,
Cache: () => Cache.test(
processManager: FakeProcessManager.any(),
processManager: processManager,
),
});

testUsingContext('force updates packages --synthetic-package-path', () async {
final UpdatePackagesCommand command = UpdatePackagesCommand();
const String dir = '/path/to/synthetic/package';
await createTestCommandRunner(command).run(<String>[
'update-packages',
'--force-upgrade',
'--synthetic-package-path=$dir',
]);
expect(pub.pubGetDirectories, equals(<String>[
'$dir/synthetic_package',
'/flutter/examples',
'/flutter/packages/flutter',
]));
expect(pub.pubBatchDirectories, equals(<String>[
'$dir/synthetic_package',
]));
}, overrides: <Type, Generator>{
Pub: () => pub,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Cache: () => Cache.test(
processManager: processManager,
),
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void main() {
fileSystem,
flutterSdk,
<PubspecYaml>[flutterPubspec],
fileSystem.systemTempDirectory,
);

expect(result, exists);
Expand Down