OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:collection'; | 5 import 'dart:collection'; |
6 | 6 |
7 import 'package:path/path.dart' as p; | 7 import 'package:path/path.dart' as p; |
8 import 'package:package_config/packages_file.dart' as packages_file; | 8 import 'package:package_config/packages_file.dart' as packages_file; |
9 import 'package:pub_semver/pub_semver.dart'; | 9 import 'package:pub_semver/pub_semver.dart'; |
10 import 'package:source_span/source_span.dart'; | 10 import 'package:source_span/source_span.dart'; |
11 import 'package:yaml/yaml.dart'; | 11 import 'package:yaml/yaml.dart'; |
12 | 12 |
13 import 'io.dart'; | 13 import 'io.dart'; |
14 import 'package.dart'; | 14 import 'package.dart'; |
15 import 'source_registry.dart'; | 15 import 'source_registry.dart'; |
16 import 'system_cache.dart'; | 16 import 'system_cache.dart'; |
17 import 'utils.dart'; | 17 import 'utils.dart'; |
18 | 18 |
19 /// A parsed and validated `pubspec.lock` file. | 19 /// A parsed and validated `pubspec.lock` file. |
20 class LockFile { | 20 class LockFile { |
21 /// The packages this lockfile pins. | 21 /// The packages this lockfile pins. |
22 final Map<String, PackageId> packages; | 22 final Map<String, PackageId> packages; |
23 | 23 |
24 /// The intersection of all SDK constraints for all locked packages. | 24 /// The intersection of all Dart SDK constraints for all locked packages. |
25 final VersionConstraint sdkConstraint; | 25 final VersionConstraint dartSdkConstraint; |
| 26 |
| 27 /// The intersection of all Flutter SDK constraints for all locked packages, |
| 28 /// or `null` if no packages require the Flutter SDK. |
| 29 final VersionConstraint flutterSdkConstraint; |
26 | 30 |
27 /// Creates a new lockfile containing [ids]. | 31 /// Creates a new lockfile containing [ids]. |
28 /// | 32 /// |
29 /// If passed, [sdkConstraint] represents the intersection of all SKD | 33 /// If passed, [dartSdkConstraint] represents the intersection of all Dart SDK |
30 /// constraints for all locked packages. It defaults to | 34 /// constraints for all locked packages. It defaults to |
31 /// [VersionConstraint.any]. | 35 /// [VersionConstraint.any]. Similarly, [flutterSdkConstraint] represents the |
32 LockFile(Iterable<PackageId> ids, {VersionConstraint sdkConstraint}) | 36 /// intersection of all Flutter SDK constraints; however, it defaults to |
| 37 /// `null`. |
| 38 LockFile(Iterable<PackageId> ids, {VersionConstraint dartSdkConstraint, |
| 39 VersionConstraint flutterSdkConstraint}) |
33 : this._( | 40 : this._( |
34 new Map.fromIterable( | 41 new Map.fromIterable( |
35 ids.where((id) => !id.isRoot), | 42 ids.where((id) => !id.isRoot), |
36 key: (id) => id.name), | 43 key: (id) => id.name), |
37 sdkConstraint ?? VersionConstraint.any); | 44 dartSdkConstraint ?? VersionConstraint.any, |
| 45 flutterSdkConstraint); |
38 | 46 |
39 LockFile._(Map<String, PackageId> packages, this.sdkConstraint) | 47 LockFile._(Map<String, PackageId> packages, this.dartSdkConstraint, |
| 48 this.flutterSdkConstraint) |
40 : packages = new UnmodifiableMapView(packages); | 49 : packages = new UnmodifiableMapView(packages); |
41 | 50 |
42 LockFile.empty() | 51 LockFile.empty() |
43 : packages = const {}, | 52 : packages = const {}, |
44 sdkConstraint = VersionConstraint.any; | 53 dartSdkConstraint = VersionConstraint.any, |
| 54 flutterSdkConstraint = null; |
45 | 55 |
46 /// Loads a lockfile from [filePath]. | 56 /// Loads a lockfile from [filePath]. |
47 factory LockFile.load(String filePath, SourceRegistry sources) { | 57 factory LockFile.load(String filePath, SourceRegistry sources) { |
48 return LockFile._parse(filePath, readTextFile(filePath), sources); | 58 return LockFile._parse(filePath, readTextFile(filePath), sources); |
49 } | 59 } |
50 | 60 |
51 /// Parses a lockfile whose text is [contents]. | 61 /// Parses a lockfile whose text is [contents]. |
52 factory LockFile.parse(String contents, SourceRegistry sources) { | 62 factory LockFile.parse(String contents, SourceRegistry sources) { |
53 return LockFile._parse(null, contents, sources); | 63 return LockFile._parse(null, contents, sources); |
54 } | 64 } |
55 | 65 |
56 /// Parses the lockfile whose text is [contents]. | 66 /// Parses the lockfile whose text is [contents]. |
57 /// | 67 /// |
58 /// [filePath] is the system-native path to the lockfile on disc. It may be | 68 /// [filePath] is the system-native path to the lockfile on disc. It may be |
59 /// `null`. | 69 /// `null`. |
60 static LockFile _parse(String filePath, String contents, | 70 static LockFile _parse(String filePath, String contents, |
61 SourceRegistry sources) { | 71 SourceRegistry sources) { |
62 if (contents.trim() == '') return new LockFile.empty(); | 72 if (contents.trim() == '') return new LockFile.empty(); |
63 | 73 |
64 var sourceUrl; | 74 var sourceUrl; |
65 if (filePath != null) sourceUrl = p.toUri(filePath); | 75 if (filePath != null) sourceUrl = p.toUri(filePath); |
66 var parsed = loadYamlNode(contents, sourceUrl: sourceUrl); | 76 var parsed = loadYamlNode(contents, sourceUrl: sourceUrl); |
67 | 77 |
68 _validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed); | 78 _validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed); |
69 | 79 |
70 var sdkConstraint = VersionConstraint.any; | 80 var dartSdkConstraint = VersionConstraint.any; |
71 var sdkConstraintText = parsed['sdk']; | 81 VersionConstraint flutterSdkConstraint; |
72 if (sdkConstraintText != null) { | 82 var sdkNode = parsed.nodes['sdk']; |
| 83 if (sdkNode != null) { |
| 84 // Lockfiles produced by pub versions from 1.14.0 through 1.18.0 included |
| 85 // a top-level "sdk" field which encoded the unified constraint on the |
| 86 // Dart SDK. They had no way of specifying constraints on other SDKs. |
| 87 dartSdkConstraint = _parseVersionConstraint(sdkNode); |
| 88 } else if ((parsed as Map).containsKey('sdks')) { |
| 89 var sdksField = parsed['sdks']; |
73 _validate( | 90 _validate( |
74 sdkConstraintText is String, | 91 sdksField is Map, |
75 'The "sdk" field must be a string.', | 92 'The "sdks" field must be a mapping.', |
76 parsed.nodes['sdk']); | 93 parsed.nodes['sdks']); |
77 | 94 |
78 sdkConstraint = _wrapFormatException( | 95 dartSdkConstraint = _parseVersionConstraint(sdksField.nodes['dart']); |
79 'version constraint', | 96 flutterSdkConstraint = |
80 parsed.nodes['sdk'].span, | 97 _parseVersionConstraint(sdksField.nodes['flutter']); |
81 () => new VersionConstraint.parse(sdkConstraintText)); | |
82 } | 98 } |
83 | 99 |
84 var packages = {}; | 100 var packages = {}; |
85 var packageEntries = parsed['packages']; | 101 var packageEntries = parsed['packages']; |
86 if (packageEntries != null) { | 102 if (packageEntries != null) { |
87 _validate(packageEntries is Map, 'The "packages" field must be a map.', | 103 _validate(packageEntries is Map, 'The "packages" field must be a map.', |
88 parsed.nodes['packages']); | 104 parsed.nodes['packages']); |
89 | 105 |
90 packageEntries.forEach((name, spec) { | 106 packageEntries.forEach((name, spec) { |
91 // Parse the version. | 107 // Parse the version. |
(...skipping 21 matching lines...) Expand all Loading... |
113 } | 129 } |
114 | 130 |
115 // Validate the name. | 131 // Validate the name. |
116 _validate(name == id.name, | 132 _validate(name == id.name, |
117 "Package name $name doesn't match ${id.name}.", spec); | 133 "Package name $name doesn't match ${id.name}.", spec); |
118 | 134 |
119 packages[name] = id; | 135 packages[name] = id; |
120 }); | 136 }); |
121 } | 137 } |
122 | 138 |
123 return new LockFile._(packages, sdkConstraint); | 139 return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint); |
| 140 } |
| 141 |
| 142 /// Asserts that [node] is a version constraint, and parses it. |
| 143 static VersionConstraint _parseVersionConstraint(YamlNode node) { |
| 144 if (node == null) return null; |
| 145 |
| 146 _validate( |
| 147 node.value is String, |
| 148 'Invalid version constraint: must be a string.', |
| 149 node); |
| 150 |
| 151 return _wrapFormatException( |
| 152 'version constraint', |
| 153 node.span, |
| 154 () => new VersionConstraint.parse(node.value)); |
124 } | 155 } |
125 | 156 |
126 /// Runs [fn] and wraps any [FormatException] it throws in a | 157 /// Runs [fn] and wraps any [FormatException] it throws in a |
127 /// [SourceSpanFormatException]. | 158 /// [SourceSpanFormatException]. |
128 /// | 159 /// |
129 /// [description] should be a noun phrase that describes whatever's being | 160 /// [description] should be a noun phrase that describes whatever's being |
130 /// parsed or processed by [fn]. [span] should be the location of whatever's | 161 /// parsed or processed by [fn]. [span] should be the location of whatever's |
131 /// being processed within the pubspec. | 162 /// being processed within the pubspec. |
132 static _wrapFormatException(String description, SourceSpan span, fn()) { | 163 static _wrapFormatException(String description, SourceSpan span, fn()) { |
133 try { | 164 try { |
(...skipping 12 matching lines...) Expand all Loading... |
146 | 177 |
147 /// Returns a copy of this LockFile with [id] added. | 178 /// Returns a copy of this LockFile with [id] added. |
148 /// | 179 /// |
149 /// If there's already an ID with the same name as [id] in the LockFile, it's | 180 /// If there's already an ID with the same name as [id] in the LockFile, it's |
150 /// overwritten. | 181 /// overwritten. |
151 LockFile setPackage(PackageId id) { | 182 LockFile setPackage(PackageId id) { |
152 if (id.isRoot) return this; | 183 if (id.isRoot) return this; |
153 | 184 |
154 var packages = new Map.from(this.packages); | 185 var packages = new Map.from(this.packages); |
155 packages[id.name] = id; | 186 packages[id.name] = id; |
156 return new LockFile._(packages, sdkConstraint); | 187 return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint); |
157 } | 188 } |
158 | 189 |
159 /// Returns a copy of this LockFile with a package named [name] removed. | 190 /// Returns a copy of this LockFile with a package named [name] removed. |
160 /// | 191 /// |
161 /// Returns an identical [LockFile] if there's no package named [name]. | 192 /// Returns an identical [LockFile] if there's no package named [name]. |
162 LockFile removePackage(String name) { | 193 LockFile removePackage(String name) { |
163 if (!this.packages.containsKey(name)) return this; | 194 if (!this.packages.containsKey(name)) return this; |
164 | 195 |
165 var packages = new Map.from(this.packages); | 196 var packages = new Map.from(this.packages); |
166 packages.remove(name); | 197 packages.remove(name); |
167 return new LockFile._(packages, sdkConstraint); | 198 return new LockFile._(packages, dartSdkConstraint, flutterSdkConstraint); |
168 } | 199 } |
169 | 200 |
170 /// Returns the contents of the `.packages` file generated from this lockfile. | 201 /// Returns the contents of the `.packages` file generated from this lockfile. |
171 /// | 202 /// |
172 /// If [entrypoint] is passed, a relative entry is added for its "lib/" | 203 /// If [entrypoint] is passed, a relative entry is added for its "lib/" |
173 /// directory. | 204 /// directory. |
174 String packagesFile(SystemCache cache, [String entrypoint]) { | 205 String packagesFile(SystemCache cache, [String entrypoint]) { |
175 var header = "Generated by pub on ${new DateTime.now()}."; | 206 var header = "Generated by pub on ${new DateTime.now()}."; |
176 | 207 |
177 var map = new Map.fromIterable(ordered(packages.keys), value: (name) { | 208 var map = new Map.fromIterable(ordered(packages.keys), value: (name) { |
(...skipping 20 matching lines...) Expand all Loading... |
198 var description = package.source | 229 var description = package.source |
199 .serializeDescription(packageDir, package.description); | 230 .serializeDescription(packageDir, package.description); |
200 | 231 |
201 packageMap[name] = { | 232 packageMap[name] = { |
202 'version': package.version.toString(), | 233 'version': package.version.toString(), |
203 'source': package.source.name, | 234 'source': package.source.name, |
204 'description': description | 235 'description': description |
205 }; | 236 }; |
206 }); | 237 }); |
207 | 238 |
208 var data = {'sdk': sdkConstraint.toString(), 'packages': packageMap}; | 239 var sdks = { |
| 240 'dart': dartSdkConstraint.toString() |
| 241 }; |
| 242 if (flutterSdkConstraint != null) { |
| 243 sdks['flutter'] = flutterSdkConstraint.toString(); |
| 244 } |
| 245 |
| 246 var data = {'sdks': sdks, 'packages': packageMap}; |
209 return """ | 247 return """ |
210 # Generated by pub | 248 # Generated by pub |
211 # See http://pub.dartlang.org/doc/glossary.html#lockfile | 249 # See http://pub.dartlang.org/doc/glossary.html#lockfile |
212 ${yamlToString(data)} | 250 ${yamlToString(data)} |
213 """; | 251 """; |
214 } | 252 } |
215 } | 253 } |
OLD | NEW |