Skip to content

Commit 0b9d18f

Browse files
[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
1 parent ce2fa9a commit 0b9d18f

File tree

3 files changed

+114
-63
lines changed

3 files changed

+114
-63
lines changed

packages/flutter_tools/lib/src/commands/update_packages.dart

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,25 @@ class UpdatePackagesCommand extends FlutterCommand {
9999
abbr: 'j',
100100
help: 'Causes the "pub get" runs to happen concurrently on this many '
101101
'CPUs. Defaults to the number of CPUs that this machine has.',
102+
)
103+
..addOption(
104+
'synthetic-package-path',
105+
help: 'Write the synthetic monolithic pub package generated to do '
106+
'version solving to a persistent path. By default, a temporary '
107+
'directory that is deleted before the command exits. By '
108+
'providing this path, a Flutter maintainer can inspect further '
109+
'exactly how version solving was achieved.',
102110
);
103111
}
104112

105113
@override
106114
final String name = 'update-packages';
107115

108116
@override
109-
final String description = 'Update the packages inside the Flutter repo.';
117+
final String description = 'Update the packages inside the Flutter repo. '
118+
'This is intended for CI and repo maintainers. '
119+
'Normal Flutter developers should not have to '
120+
'use this command.';
110121

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

158+
late final Directory _syntheticPackageDir = (() {
159+
final String? optionPath = stringArg('synthetic-package-path');
160+
if (optionPath == null) {
161+
return globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.');
162+
}
163+
final Directory syntheticPackageDir = globals.fs.directory(optionPath);
164+
if (!syntheticPackageDir.existsSync()) {
165+
syntheticPackageDir.createSync(recursive: true);
166+
}
167+
globals.printStatus(
168+
'The synthetic package with all pub dependencies across the repo will '
169+
'be written to ${syntheticPackageDir.absolute.path}.',
170+
);
171+
return syntheticPackageDir;
172+
})();
173+
147174
@override
148175
Future<FlutterCommandResult> runCommand() async {
149176
final List<Directory> packages = runner!.getRepoPackages();
@@ -218,15 +245,19 @@ class UpdatePackagesCommand extends FlutterCommand {
218245
// attempt to download any necessary package versions to the pub cache to
219246
// warm the cache.
220247
final PubDependencyTree tree = PubDependencyTree(); // object to collect results
221-
final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_update_packages.');
222248
await _generateFakePackage(
223-
tempDir: tempDir,
249+
tempDir: _syntheticPackageDir,
224250
dependencies: doUpgrade ? explicitDependencies.values : allDependencies.values,
225251
pubspecs: pubspecs,
226252
tree: tree,
227253
doUpgrade: doUpgrade,
228254
);
229255

256+
// Only delete the synthetic package if it was done in a temp directory
257+
if (stringArg('synthetic-package-path') == null) {
258+
_syntheticPackageDir.deleteSync(recursive: true);
259+
}
260+
230261
if (doUpgrade) {
231262
final bool done = _upgradePubspecs(
232263
tree: tree,
@@ -380,57 +411,49 @@ class UpdatePackagesCommand extends FlutterCommand {
380411
required bool doUpgrade,
381412
}) async {
382413
Directory? temporaryFlutterSdk;
383-
try {
384-
final File fakePackage = _pubspecFor(tempDir);
385-
fakePackage.createSync();
386-
fakePackage.writeAsStringSync(
387-
generateFakePubspec(
388-
dependencies,
389-
doUpgrade: doUpgrade,
390-
),
414+
final Directory syntheticPackageDir = tempDir.childDirectory('synthetic_package');
415+
final File fakePackage = _pubspecFor(syntheticPackageDir);
416+
fakePackage.createSync(recursive: true);
417+
fakePackage.writeAsStringSync(
418+
generateFakePubspec(
419+
dependencies,
420+
doUpgrade: doUpgrade,
421+
),
422+
);
423+
// Create a synthetic flutter SDK so that transitive flutter SDK
424+
// constraints are not affected by this upgrade.
425+
if (doUpgrade) {
426+
temporaryFlutterSdk = createTemporaryFlutterSdk(
427+
globals.logger,
428+
globals.fs,
429+
globals.fs.directory(Cache.flutterRoot),
430+
pubspecs,
431+
tempDir,
391432
);
392-
// Create a synthetic flutter SDK so that transitive flutter SDK
393-
// constraints are not affected by this upgrade.
394-
if (doUpgrade) {
395-
temporaryFlutterSdk = createTemporaryFlutterSdk(
396-
globals.logger,
397-
globals.fs,
398-
globals.fs.directory(Cache.flutterRoot),
399-
pubspecs,
400-
);
401-
}
433+
}
402434

403-
// Next we run "pub get" on it in order to force the download of any
404-
// needed packages to the pub cache, upgrading if requested.
405-
await pub.get(
435+
// Next we run "pub get" on it in order to force the download of any
436+
// needed packages to the pub cache, upgrading if requested.
437+
await pub.get(
438+
context: PubContext.updatePackages,
439+
project: FlutterProject.fromDirectory(syntheticPackageDir),
440+
upgrade: doUpgrade,
441+
offline: boolArgDeprecated('offline'),
442+
flutterRootOverride: temporaryFlutterSdk?.path,
443+
);
444+
445+
if (doUpgrade) {
446+
// If upgrading, we run "pub deps --style=compact" on the result. We
447+
// pipe all the output to tree.fill(), which parses it so that it can
448+
// create a graph of all the dependencies so that we can figure out the
449+
// transitive dependencies later. It also remembers which version was
450+
// selected for each package.
451+
await pub.batch(
452+
<String>['deps', '--style=compact'],
406453
context: PubContext.updatePackages,
407-
project: FlutterProject.fromDirectory(tempDir),
408-
upgrade: doUpgrade,
409-
offline: boolArgDeprecated('offline'),
410-
flutterRootOverride: temporaryFlutterSdk?.path,
454+
directory: syntheticPackageDir.path,
455+
filter: tree.fill,
411456
);
412-
413-
if (doUpgrade) {
414-
// If upgrading, we run "pub deps --style=compact" on the result. We
415-
// pipe all the output to tree.fill(), which parses it so that it can
416-
// create a graph of all the dependencies so that we can figure out the
417-
// transitive dependencies later. It also remembers which version was
418-
// selected for each package.
419-
await pub.batch(
420-
<String>['deps', '--style=compact'],
421-
context: PubContext.updatePackages,
422-
directory: tempDir.path,
423-
filter: tree.fill,
424-
);
425-
}
426-
} finally {
427-
// Cleanup the temporary SDK
428-
try {
429-
temporaryFlutterSdk?.deleteSync(recursive: true);
430-
} on FileSystemException {
431-
// Failed to delete temporary SDK.
432-
}
433-
tempDir.deleteSync(recursive: true);
434457
}
435458
}
436459

@@ -1577,6 +1600,7 @@ Directory createTemporaryFlutterSdk(
15771600
FileSystem fileSystem,
15781601
Directory realFlutter,
15791602
List<PubspecYaml> pubspecs,
1603+
Directory tempDir,
15801604
) {
15811605
final Set<String> currentPackages = <String>{};
15821606
for (final FileSystemEntity entity in realFlutter.childDirectory('packages').listSync()) {
@@ -1591,8 +1615,7 @@ Directory createTemporaryFlutterSdk(
15911615
pubspecsByName[pubspec.name] = pubspec;
15921616
}
15931617

1594-
final Directory directory = fileSystem.systemTempDirectory
1595-
.createTempSync('flutter_upgrade_sdk.')
1618+
final Directory directory = tempDir.childDirectory('flutter_upgrade_sdk')
15961619
..createSync();
15971620
// Fill in version info.
15981621
realFlutter.childFile('version')

packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ void main() {
8787
late Directory flutterSdk;
8888
late Directory flutter;
8989
late FakePub pub;
90+
late FakeProcessManager processManager;
9091

9192
setUpAll(() {
9293
Cache.disableLocking();
@@ -105,23 +106,24 @@ void main() {
105106
flutter.childFile('pubspec.yaml').writeAsStringSync(kFlutterPubspecYaml);
106107
Cache.flutterRoot = flutterSdk.absolute.path;
107108
pub = FakePub(fileSystem);
109+
processManager = FakeProcessManager.empty();
108110
});
109111

110112
testUsingContext('updates packages', () async {
111113
final UpdatePackagesCommand command = UpdatePackagesCommand();
112114
await createTestCommandRunner(command).run(<String>['update-packages']);
113115
expect(pub.pubGetDirectories, equals(<String>[
114-
'/.tmp_rand0/flutter_update_packages.rand0',
116+
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
115117
'/flutter/examples',
116118
'/flutter/packages/flutter',
117119
]));
118120
expect(pub.pubBatchDirectories, isEmpty);
119121
}, overrides: <Type, Generator>{
120122
Pub: () => pub,
121123
FileSystem: () => fileSystem,
122-
ProcessManager: () => FakeProcessManager.any(),
124+
ProcessManager: () => processManager,
123125
Cache: () => Cache.test(
124-
processManager: FakeProcessManager.any(),
126+
processManager: processManager,
125127
),
126128
});
127129

@@ -132,19 +134,19 @@ void main() {
132134
'--force-upgrade',
133135
]);
134136
expect(pub.pubGetDirectories, equals(<String>[
135-
'/.tmp_rand0/flutter_update_packages.rand0',
137+
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
136138
'/flutter/examples',
137139
'/flutter/packages/flutter',
138140
]));
139141
expect(pub.pubBatchDirectories, equals(<String>[
140-
'/.tmp_rand0/flutter_update_packages.rand0',
142+
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
141143
]));
142144
}, overrides: <Type, Generator>{
143145
Pub: () => pub,
144146
FileSystem: () => fileSystem,
145-
ProcessManager: () => FakeProcessManager.any(),
147+
ProcessManager: () => processManager,
146148
Cache: () => Cache.test(
147-
processManager: FakeProcessManager.any(),
149+
processManager: processManager,
148150
),
149151
});
150152

@@ -156,19 +158,44 @@ void main() {
156158
'--jobs=1',
157159
]);
158160
expect(pub.pubGetDirectories, equals(<String>[
159-
'/.tmp_rand0/flutter_update_packages.rand0',
161+
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
160162
'/flutter/examples',
161163
'/flutter/packages/flutter',
162164
]));
163165
expect(pub.pubBatchDirectories, equals(<String>[
164-
'/.tmp_rand0/flutter_update_packages.rand0',
166+
'/.tmp_rand0/flutter_update_packages.rand0/synthetic_package',
165167
]));
166168
}, overrides: <Type, Generator>{
167169
Pub: () => pub,
168170
FileSystem: () => fileSystem,
169-
ProcessManager: () => FakeProcessManager.any(),
171+
ProcessManager: () => processManager,
170172
Cache: () => Cache.test(
171-
processManager: FakeProcessManager.any(),
173+
processManager: processManager,
174+
),
175+
});
176+
177+
testUsingContext('force updates packages --synthetic-package-path', () async {
178+
final UpdatePackagesCommand command = UpdatePackagesCommand();
179+
const String dir = '/path/to/synthetic/package';
180+
await createTestCommandRunner(command).run(<String>[
181+
'update-packages',
182+
'--force-upgrade',
183+
'--synthetic-package-path=$dir',
184+
]);
185+
expect(pub.pubGetDirectories, equals(<String>[
186+
'$dir/synthetic_package',
187+
'/flutter/examples',
188+
'/flutter/packages/flutter',
189+
]));
190+
expect(pub.pubBatchDirectories, equals(<String>[
191+
'$dir/synthetic_package',
192+
]));
193+
}, overrides: <Type, Generator>{
194+
Pub: () => pub,
195+
FileSystem: () => fileSystem,
196+
ProcessManager: () => processManager,
197+
Cache: () => Cache.test(
198+
processManager: processManager,
172199
),
173200
});
174201
});

packages/flutter_tools/test/general.shard/update_packages_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ void main() {
121121
fileSystem,
122122
flutterSdk,
123123
<PubspecYaml>[flutterPubspec],
124+
fileSystem.systemTempDirectory,
124125
);
125126

126127
expect(result, exists);

0 commit comments

Comments
 (0)