dependency_services: Don't download archives on apply (#3352)
diff --git a/lib/src/command/dependency_services.dart b/lib/src/command/dependency_services.dart
index 0e731f4..47dcfa4 100644
--- a/lib/src/command/dependency_services.dart
+++ b/lib/src/command/dependency_services.dart
@@ -13,9 +13,9 @@
import 'package:yaml_edit/yaml_edit.dart';
import '../command.dart';
-import '../entrypoint.dart';
import '../exceptions.dart';
import '../io.dart';
+import '../lock_file.dart';
import '../log.dart' as log;
import '../package.dart';
import '../package_name.dart';
@@ -275,10 +275,10 @@
}
enum UpgradeType {
- /// Only upgrade pubspec.lock
+ /// Only upgrade pubspec.lock.
compatible,
- /// Unlock at most one dependency in pubspec.yaml
+ /// Unlock at most one dependency in pubspec.yaml.
singleBreaking,
/// Unlock any dependencies in pubspec.yaml needed for getting the
@@ -292,7 +292,7 @@
@override
String get description =>
- 'Output a machine digestible listing of all dependencies';
+ 'Updates pubspec.yaml and pubspec.lock according to input.';
@override
bool get takesArguments => true;
@@ -362,17 +362,32 @@
}
}
- if (pubspecEditor.edits.isNotEmpty) {
- writeTextFile(entrypoint.pubspecPath, pubspecEditor.toString());
- }
- if (lockFileEditor != null && lockFileEditor.edits.isNotEmpty) {
- writeTextFile(entrypoint.lockFilePath, lockFileEditor.toString());
- }
+ final updatedLockfile = lockFileEditor == null
+ ? null
+ : LockFile.parse(lockFileEditor.toString(), cache.sources);
await log.warningsOnlyUnlessTerminal(
() async {
- // This will fail if the new configuration does not resolve.
- await Entrypoint(directory, cache).acquireDependencies(SolveType.get,
- analytics: null, generateDotPackages: false);
+ final updatedPubspec = pubspecEditor.toString();
+ // Resolve versions, this will update transitive dependencies that were
+ // not passed in the input. And also counts as a validation of the input
+ // by ensuring the resolution is valid.
+ //
+ // We don't use `acquireDependencies` as that downloads all the archives
+ // to cache.
+ // TODO: Handle HTTP exceptions gracefully!
+ final solveResult = await resolveVersions(
+ SolveType.get,
+ cache,
+ Package.inMemory(Pubspec.parse(updatedPubspec, cache.sources)),
+ lockFile: updatedLockfile,
+ );
+ if (pubspecEditor.edits.isNotEmpty) {
+ writeTextFile(entrypoint.pubspecPath, updatedPubspec);
+ }
+ // Only if we originally had a lock-file we write the resulting lockfile back.
+ if (lockFileEditor != null) {
+ entrypoint.saveLockFile(solveResult);
+ }
},
);
// Dummy message.
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index 202580c..e854d52 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -313,7 +313,7 @@
}
if (!dryRun) {
await result.downloadCachedPackages(cache);
- _saveLockFile(result);
+ saveLockFile(result);
}
if (onlyReportSuccessOrFailure) {
log.message('Got dependencies$suffix.');
@@ -844,7 +844,7 @@
///
/// Will use Windows line endings (`\r\n`) if a `pubspec.lock` exists, and
/// uses that.
- void _saveLockFile(SolveResult result) {
+ void saveLockFile(SolveResult result) {
_lockFile = result.lockFile;
final windowsLineEndings = fileExists(lockFilePath) &&
diff --git a/test/dependency_services/dependency_services_test.dart b/test/dependency_services/dependency_services_test.dart
index 694e229..ed21a19 100644
--- a/test/dependency_services/dependency_services_test.dart
+++ b/test/dependency_services/dependency_services_test.dart
@@ -8,6 +8,7 @@
import 'package:path/path.dart' as p;
import 'package:pub/src/io.dart';
import 'package:pub_semver/pub_semver.dart';
+import 'package:shelf/shelf.dart' as shelf;
import 'package:test/test.dart';
import '../descriptor.dart' as d;
@@ -110,7 +111,7 @@
});
testWithGolden('Removing transitive', (context) async {
- (await servePackages())
+ final server = (await servePackages())
..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'})
..serve('foo', '2.2.3')
..serve('transitive', '1.0.0');
@@ -124,6 +125,7 @@
})
]).create();
await pubGet();
+ server.dontAllowDownloads();
await listReportApply(context, [
_PackageVersion('foo', Version.parse('2.2.3')),
_PackageVersion('transitive', null)
@@ -146,6 +148,7 @@
..serve('bar', '1.2.3')
..serve('bar', '2.2.3')
..serve('boo', '1.2.3');
+
await d.dir(appPath, [
d.pubspec({
'name': 'app',
@@ -160,6 +163,8 @@
server.serve('foo', '1.2.4');
server.serve('boo', '1.2.4');
+ server.dontAllowDownloads();
+
await listReportApply(context, [
_PackageVersion('foo', Version.parse('1.2.4')),
], reportAssertions: (report) {
@@ -171,7 +176,7 @@
});
testWithGolden('Adding transitive', (context) async {
- (await servePackages())
+ final server = (await servePackages())
..serve('foo', '1.2.3')
..serve('foo', '2.2.3', deps: {'transitive': '^1.0.0'})
..serve('transitive', '1.0.0');
@@ -185,6 +190,8 @@
})
]).create();
await pubGet();
+ server.dontAllowDownloads();
+
await listReportApply(context, [
_PackageVersion('foo', Version.parse('2.2.3')),
_PackageVersion('transitive', Version.parse('1.0.0'))
@@ -225,6 +232,9 @@
..serve('foo', '3.0.1', deps: {'bar': '^2.0.0'})
..serve('bar', '2.0.0', deps: {'foo': '^3.0.0'})
..serve('baz', '1.1.0');
+
+ server.dontAllowDownloads();
+
await listReportApply(context, [
_PackageVersion('foo', Version.parse('3.0.1'),
constraint: VersionConstraint.parse('^3.0.0')),
@@ -259,3 +269,17 @@
if (constraint != null) 'constraint': constraint.toString()
};
}
+
+extension on PackageServer {
+ ///Check that nothing is downloaded.
+ void dontAllowDownloads() {
+ // This testing logic is a bit fragile, if we change the pattern for pattern
+ // for the download URL then this will pass silently. There isn't much we
+ // can / should do about it. Just accept the limitations, and remove it if
+ // the test becomes useless.
+ handle(RegExp(r'/.+\.tar\.gz'), (request) {
+ return shelf.Response.notFound(
+ 'This test should not download archives! Requested ${request.url}');
+ });
+ }
+}