Unverified Commit 0b9d18f8 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] Add flutter update-packages --synthetic-package-path (#115665)

* allow persisting synthetic package with option

* allow presisting synthetic packages dir

* fix

* fix bug and add tests

* clean up tests

* nits
parent ce2fa9a5
......@@ -99,6 +99,14 @@ 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.',
);
}
......@@ -106,7 +114,10 @@ class UpdatePackagesCommand extends FlutterCommand {
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'];
......@@ -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();
......@@ -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,
......@@ -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);
} on FileSystemException {
// Failed to delete temporary SDK.
}
tempDir.deleteSync(recursive: true);
}
}
......@@ -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()) {
......@@ -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')
......
......@@ -87,6 +87,7 @@ void main() {
late Directory flutterSdk;
late Directory flutter;
late FakePub pub;
late FakeProcessManager processManager;
setUpAll(() {
Cache.disableLocking();
......@@ -105,13 +106,14 @@ 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',
]));
......@@ -119,9 +121,9 @@ void main() {
}, overrides: <Type, Generator>{
Pub: () => pub,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
ProcessManager: () => processManager,
Cache: () => Cache.test(
processManager: FakeProcessManager.any(),
processManager: processManager,
),
});
......@@ -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,
),
});
......@@ -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,
),
});
});
......
......@@ -121,6 +121,7 @@ void main() {
fileSystem,
flutterSdk,
<PubspecYaml>[flutterPubspec],
fileSystem.systemTempDirectory,
);
expect(result, exists);
......
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