Skip to content

Commit be28505

Browse files
authored
Indicate the source of a dependency in the lockfile (#1722)
Indicate the source of a dependency in the lockfile Closes #1721
1 parent a4f5789 commit be28505

File tree

4 files changed

+141
-25
lines changed

4 files changed

+141
-25
lines changed

lib/src/lock_file.dart

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:collection';
66

7+
import 'package:collection/collection.dart';
78
import 'package:path/path.dart' as p;
89
import 'package:package_config/packages_file.dart' as packages_file;
910
import 'package:pub_semver/pub_semver.dart';
@@ -28,30 +29,62 @@ class LockFile {
2829
/// or `null` if no packages require the Flutter SDK.
2930
final VersionConstraint flutterSdkConstraint;
3031

32+
/// Dependency names that appeared in the root package's `dependencies`
33+
/// section.
34+
final Set<String> _mainDependencies;
35+
36+
/// Dependency names that appeared in the root package's `dev_dependencies`
37+
/// section.
38+
final Set<String> _devDependencies;
39+
40+
/// Dependency names that appeared in the root package's
41+
/// `dependency_overrides` section.
42+
final Set<String> _overriddenDependencies;
43+
3144
/// Creates a new lockfile containing [ids].
3245
///
3346
/// If passed, [dartSdkConstraint] represents the intersection of all Dart SDK
3447
/// constraints for all locked packages. It defaults to
3548
/// [VersionConstraint.any]. Similarly, [flutterSdkConstraint] represents the
3649
/// intersection of all Flutter SDK constraints; however, it defaults to
3750
/// `null`.
51+
///
52+
/// If passed, [mainDependencies], [devDependencies], and
53+
/// [overriddenDependencies] indicate which dependencies should be marked as
54+
/// being listed in the main package's `dependencies`, `dev_dependencies`, and
55+
/// `dependency_overrides` sections, respectively. These are consumed by the
56+
/// analysis server to provide better auto-completion.
3857
LockFile(Iterable<PackageId> ids,
3958
{VersionConstraint dartSdkConstraint,
40-
VersionConstraint flutterSdkConstraint})
59+
VersionConstraint flutterSdkConstraint,
60+
Set<String> mainDependencies,
61+
Set<String> devDependencies,
62+
Set<String> overriddenDependencies})
4163
: this._(
4264
new Map.fromIterable(ids.where((id) => !id.isRoot),
4365
key: (id) => id.name),
4466
dartSdkConstraint ?? VersionConstraint.any,
45-
flutterSdkConstraint);
46-
47-
LockFile._(Map<String, PackageId> packages, this.dartSdkConstraint,
48-
this.flutterSdkConstraint)
67+
flutterSdkConstraint,
68+
mainDependencies ?? const UnmodifiableSetView.empty(),
69+
devDependencies ?? const UnmodifiableSetView.empty(),
70+
overriddenDependencies ?? const UnmodifiableSetView.empty());
71+
72+
LockFile._(
73+
Map<String, PackageId> packages,
74+
this.dartSdkConstraint,
75+
this.flutterSdkConstraint,
76+
this._mainDependencies,
77+
this._devDependencies,
78+
this._overriddenDependencies)
4979
: packages = new UnmodifiableMapView(packages);
5080

5181
LockFile.empty()
5282
: packages = const {},
5383
dartSdkConstraint = VersionConstraint.any,
54-
flutterSdkConstraint = null;
84+
flutterSdkConstraint = null,
85+
_mainDependencies = const UnmodifiableSetView.empty(),
86+
_devDependencies = const UnmodifiableSetView.empty(),
87+
_overriddenDependencies = const UnmodifiableSetView.empty();
5588

5689
/// Loads a lockfile from [filePath].
5790
factory LockFile.load(String filePath, SourceRegistry sources) {
@@ -135,7 +168,13 @@ class LockFile {
135168
});
136169
}
137170

138-
return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint);
171+
return new LockFile._(
172+
packages,
173+
dartSdkConstraint,
174+
flutterSdkConstraint,
175+
const UnmodifiableSetView.empty(),
176+
const UnmodifiableSetView.empty(),
177+
const UnmodifiableSetView.empty());
139178
}
140179

141180
/// Asserts that [node] is a version constraint, and parses it.
@@ -170,18 +209,6 @@ class LockFile {
170209
throw new SourceSpanFormatException(message, node.span);
171210
}
172211

173-
/// Returns a copy of this LockFile with [id] added.
174-
///
175-
/// If there's already an ID with the same name as [id] in the LockFile, it's
176-
/// overwritten.
177-
LockFile setPackage(PackageId id) {
178-
if (id.isRoot) return this;
179-
180-
var packages = new Map<String, PackageId>.from(this.packages);
181-
packages[id.name] = id;
182-
return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint);
183-
}
184-
185212
/// Returns a copy of this LockFile with a package named [name] removed.
186213
///
187214
/// Returns an identical [LockFile] if there's no package named [name].
@@ -190,7 +217,8 @@ class LockFile {
190217

191218
var packages = new Map<String, PackageId>.from(this.packages);
192219
packages.remove(name);
193-
return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint);
220+
return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint,
221+
_mainDependencies, _devDependencies, _overriddenDependencies);
194222
}
195223

196224
/// Returns the contents of the `.packages` file generated from this lockfile.
@@ -228,7 +256,8 @@ class LockFile {
228256
packageMap[name] = {
229257
'version': package.version.toString(),
230258
'source': package.source.name,
231-
'description': description
259+
'description': description,
260+
'dependency': _dependencyType(package.name)
232261
};
233262
});
234263

@@ -244,4 +273,17 @@ class LockFile {
244273
${yamlToString(data)}
245274
""";
246275
}
276+
277+
/// Returns the dependency classification for [package].
278+
String _dependencyType(String package) {
279+
if (_mainDependencies.contains(package)) return 'direct main';
280+
if (_devDependencies.contains(package)) return 'direct dev';
281+
282+
// If a package appears in `dependency_overrides` and another dependency
283+
// section, the main section it appears in takes precedence.
284+
if (_overriddenDependencies.contains(package)) {
285+
return 'direct overridden';
286+
}
287+
return 'transitive';
288+
}
247289
}

lib/src/solver/version_solver.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,13 @@ class SolveResult {
9999
: new VersionConstraint.intersection(flutterConstraints);
100100

101101
return new LockFile(packages,
102-
dartSdkConstraint: dartMerged, flutterSdkConstraint: flutterMerged);
102+
dartSdkConstraint: dartMerged,
103+
flutterSdkConstraint: flutterMerged,
104+
mainDependencies: _root.dependencies.map((range) => range.name).toSet(),
105+
devDependencies:
106+
_root.devDependencies.map((range) => range.name).toSet(),
107+
overriddenDependencies:
108+
_root.dependencyOverrides.map((range) => range.name).toSet());
103109
}
104110

105111
final SourceRegistry _sources;

test/get/hosted/get_test.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:path/path.dart' as p;
56
import 'package:test/test.dart';
7+
import 'package:yaml/yaml.dart';
68

79
import 'package:pub/src/exit_codes.dart' as exit_codes;
10+
import 'package:pub/src/io.dart';
811

912
import '../../descriptor.dart' as d;
1013
import '../../test_pub.dart';
@@ -53,4 +56,67 @@ main() {
5356
await d.cacheDir({"foo": "1.2.3"}, port: server.port).validate();
5457
await d.appPackagesFile({"foo": "1.2.3"}).validate();
5558
});
59+
60+
group('categorizes dependency types in the lockfile', () {
61+
setUp(() => servePackages((builder) {
62+
builder.serve("foo", "1.2.3", deps: {"bar": "any"});
63+
builder.serve("bar", "1.2.3");
64+
builder.serve("baz", "1.2.3", deps: {"qux": "any"});
65+
builder.serve("qux", "1.2.3");
66+
builder.serve("zip", "1.2.3", deps: {"zap": "any"});
67+
builder.serve("zap", "1.2.3");
68+
}));
69+
70+
test('for main, dev, and overridden dependencies', () async {
71+
await d.dir(appPath, [
72+
d.pubspec({
73+
"name": "myapp",
74+
"dependencies": {"foo": "any"},
75+
"dev_dependencies": {"baz": "any"},
76+
"dependency_overrides": {"zip": "any"}
77+
})
78+
]).create();
79+
80+
await pubGet();
81+
82+
var packages = loadYaml(
83+
readTextFile(p.join(d.sandbox, appPath, 'pubspec.lock')))['packages'];
84+
expect(packages,
85+
containsPair('foo', containsPair('dependency', 'direct main')));
86+
expect(packages,
87+
containsPair('bar', containsPair('dependency', 'transitive')));
88+
expect(packages,
89+
containsPair('baz', containsPair('dependency', 'direct dev')));
90+
expect(packages,
91+
containsPair('qux', containsPair('dependency', 'transitive')));
92+
expect(packages,
93+
containsPair('zip', containsPair('dependency', 'direct overridden')));
94+
expect(packages,
95+
containsPair('zap', containsPair('dependency', 'transitive')));
96+
});
97+
98+
test('for overridden main and dev dependencies', () async {
99+
await d.dir(appPath, [
100+
d.pubspec({
101+
"name": "myapp",
102+
"dependencies": {"foo": "any"},
103+
"dev_dependencies": {"baz": "any"},
104+
"dependency_overrides": {"foo": "any", "baz": "any"}
105+
})
106+
]).create();
107+
108+
await pubGet();
109+
110+
var packages = loadYaml(
111+
readTextFile(p.join(d.sandbox, appPath, 'pubspec.lock')))['packages'];
112+
expect(packages,
113+
containsPair('foo', containsPair('dependency', 'direct main')));
114+
expect(packages,
115+
containsPair('bar', containsPair('dependency', 'transitive')));
116+
expect(packages,
117+
containsPair('baz', containsPair('dependency', 'direct dev')));
118+
expect(packages,
119+
containsPair('qux', containsPair('dependency', 'transitive')));
120+
});
121+
});
56122
}

test/lock_file_test.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ packages:
244244
new PackageId(
245245
'foo', mockSource, new Version.parse('1.2.3'), 'foo desc'),
246246
new PackageId('bar', mockSource, new Version.parse('3.2.1'), 'bar desc')
247-
]);
247+
], devDependencies: ['bar'].toSet());
248248

249249
expect(
250250
loadYaml(lockfile.serialize(null)),
@@ -254,12 +254,14 @@ packages:
254254
'foo': {
255255
'version': '1.2.3',
256256
'source': 'mock',
257-
'description': 'foo desc'
257+
'description': 'foo desc',
258+
'dependency': 'transitive'
258259
},
259260
'bar': {
260261
'version': '3.2.1',
261262
'source': 'mock',
262-
'description': 'bar desc'
263+
'description': 'bar desc',
264+
'dependency': 'direct dev'
263265
}
264266
}
265267
}));

0 commit comments

Comments
 (0)