Warm cache with all transitive dependencies in flutter update-packages
command (#96258)
This commit is contained in:
parent
44849ab46a
commit
23e7449a07
@ -153,7 +153,7 @@ class Cache {
|
||||
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,
|
||||
|
@ -97,6 +97,12 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
}
|
||||
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
// 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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
);
|
||||
}
|
||||
|
||||
// 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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
} 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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
'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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
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 @@ class UpdatePackagesCommand extends FlutterCommand {
|
||||
|
||||
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 @@ class PubspecYaml {
|
||||
}
|
||||
|
||||
/// 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 @@ class PubspecYaml {
|
||||
// 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
|
||||
|
@ -1473,12 +1473,15 @@ abstract class FlutterCommand extends Command<void> {
|
||||
|
||||
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>[];
|
||||
}
|
||||
|
@ -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 @@ void main() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -79,36 +79,36 @@ dependencies:
|
||||
''';
|
||||
|
||||
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 @@ void main() {
|
||||
});
|
||||
|
||||
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: '
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user