Chromium Code Reviews| 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 library pub.lock_file; | 5 library pub.lock_file; |
| 6 | 6 |
| 7 import 'dart:collection'; | |
| 8 | |
| 7 import 'package:path/path.dart' as p; | 9 import 'package:path/path.dart' as p; |
| 8 import 'package:pub_semver/pub_semver.dart'; | 10 import 'package:pub_semver/pub_semver.dart'; |
| 9 import 'package:source_span/source_span.dart'; | 11 import 'package:source_span/source_span.dart'; |
| 10 import 'package:yaml/yaml.dart'; | 12 import 'package:yaml/yaml.dart'; |
| 11 | 13 |
| 12 import 'io.dart'; | 14 import 'io.dart'; |
| 13 import 'package.dart'; | 15 import 'package.dart'; |
| 14 import 'source_registry.dart'; | 16 import 'source_registry.dart'; |
| 15 import 'utils.dart'; | 17 import 'utils.dart'; |
| 16 | 18 |
| 17 /// A parsed and validated `pubspec.lock` file. | 19 /// A parsed and validated `pubspec.lock` file. |
| 18 class LockFile { | 20 class LockFile { |
| 21 /// The source registry with which the lock file's IDs are interpreted. | |
| 22 final SourceRegistry _sources; | |
| 23 | |
| 19 /// The packages this lockfile pins. | 24 /// The packages this lockfile pins. |
| 20 Map<String, PackageId> packages; | 25 final Map<String, PackageId> packages; |
| 21 | 26 |
| 22 /// Creates a new lockfile containing [ids]. | 27 /// Creates a new lockfile containing [ids]. |
| 23 factory LockFile(List<PackageId> ids) { | 28 /// |
| 24 var lockFile = new LockFile.empty(); | 29 /// Throws an [ArgumentError] if any package has an undefined source according |
|
Bob Nystrom
2015/08/07 22:19:19
Remove the bit about undefined source.
nweiz
2015/08/07 22:24:18
Done.
| |
| 30 /// to [sources] or an unresolved ID according to [Source.isResolved]. | |
| 31 factory LockFile(Iterable<PackageId> ids, SourceRegistry sources) { | |
| 32 var packages = {}; | |
| 25 for (var id in ids) { | 33 for (var id in ids) { |
| 26 if (!id.isRoot) lockFile.packages[id.name] = id; | 34 if (id.isRoot) continue; |
| 35 | |
| 36 if (!sources[id.source].isResolved(id)) { | |
| 37 throw new ArgumentError('ID "$id" is not resolved.'); | |
| 38 } | |
| 39 | |
| 40 packages[id.name] = id; | |
| 27 } | 41 } |
| 28 | 42 |
| 29 return lockFile; | 43 return new LockFile._(packages, sources); |
| 30 } | 44 } |
| 31 | 45 |
| 32 LockFile._(this.packages); | 46 LockFile._(Map<String, PackageId> packages, this._sources) |
| 47 : packages = new UnmodifiableMapView(packages); | |
| 33 | 48 |
| 34 LockFile.empty() | 49 LockFile.empty(this._sources) |
| 35 : packages = <String, PackageId>{}; | 50 : packages = const {}; |
| 36 | 51 |
| 37 /// Loads a lockfile from [filePath]. | 52 /// Loads a lockfile from [filePath]. |
| 38 factory LockFile.load(String filePath, SourceRegistry sources) { | 53 factory LockFile.load(String filePath, SourceRegistry sources) { |
| 39 return LockFile._parse(filePath, readTextFile(filePath), sources); | 54 return LockFile._parse(filePath, readTextFile(filePath), sources); |
| 40 } | 55 } |
| 41 | 56 |
| 42 /// Parses a lockfile whose text is [contents]. | 57 /// Parses a lockfile whose text is [contents]. |
| 43 factory LockFile.parse(String contents, SourceRegistry sources) { | 58 factory LockFile.parse(String contents, SourceRegistry sources) { |
| 44 return LockFile._parse(null, contents, sources); | 59 return LockFile._parse(null, contents, sources); |
| 45 } | 60 } |
| 46 | 61 |
| 47 /// Parses the lockfile whose text is [contents]. | 62 /// Parses the lockfile whose text is [contents]. |
| 48 /// | 63 /// |
| 49 /// [filePath] is the system-native path to the lockfile on disc. It may be | 64 /// [filePath] is the system-native path to the lockfile on disc. It may be |
| 50 /// `null`. | 65 /// `null`. |
| 51 static LockFile _parse(String filePath, String contents, | 66 static LockFile _parse(String filePath, String contents, |
| 52 SourceRegistry sources) { | 67 SourceRegistry sources) { |
| 53 var packages = <String, PackageId>{}; | 68 var packages = {}; |
| 54 | 69 |
| 55 if (contents.trim() == '') return new LockFile.empty(); | 70 if (contents.trim() == '') return new LockFile.empty(sources); |
| 56 | 71 |
| 57 var sourceUrl; | 72 var sourceUrl; |
| 58 if (filePath != null) sourceUrl = p.toUri(filePath); | 73 if (filePath != null) sourceUrl = p.toUri(filePath); |
| 59 var parsed = loadYamlNode(contents, sourceUrl: sourceUrl); | 74 var parsed = loadYamlNode(contents, sourceUrl: sourceUrl); |
| 60 | 75 |
| 61 _validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed); | 76 _validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed); |
| 62 | 77 |
| 63 var packageEntries = parsed['packages']; | 78 var packageEntries = parsed['packages']; |
| 64 if (packageEntries != null) { | 79 if (packageEntries != null) { |
| 65 _validate(packageEntries is Map, 'The "packages" field must be a map.', | 80 _validate(packageEntries is Map, 'The "packages" field must be a map.', |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 93 var id = new PackageId(name, sourceName, version, description); | 108 var id = new PackageId(name, sourceName, version, description); |
| 94 | 109 |
| 95 // Validate the name. | 110 // Validate the name. |
| 96 _validate(name == id.name, | 111 _validate(name == id.name, |
| 97 "Package name $name doesn't match ${id.name}.", spec); | 112 "Package name $name doesn't match ${id.name}.", spec); |
| 98 | 113 |
| 99 packages[name] = id; | 114 packages[name] = id; |
| 100 }); | 115 }); |
| 101 } | 116 } |
| 102 | 117 |
| 103 return new LockFile._(packages); | 118 return new LockFile._(packages, sources); |
| 104 } | 119 } |
| 105 | 120 |
| 106 /// If [condition] is `false` throws a format error with [message] for [node]. | 121 /// If [condition] is `false` throws a format error with [message] for [node]. |
| 107 static void _validate(bool condition, String message, YamlNode node) { | 122 static void _validate(bool condition, String message, YamlNode node) { |
| 108 if (condition) return; | 123 if (condition) return; |
| 109 throw new SourceSpanFormatException(message, node.span); | 124 throw new SourceSpanFormatException(message, node.span); |
| 110 } | 125 } |
| 111 | 126 |
| 127 /// Returns a copy of this LockFile with [id] added. | |
| 128 /// | |
| 129 /// Throws an [ArgumentError] if [id] isn't resolved according to | |
| 130 /// [Source.isResolved]. If there's already an ID with the same name as [id] | |
| 131 /// in the LockFile, it's overwritten. | |
| 132 LockFile setPackage(PackageId id) { | |
| 133 if (id.isRoot) return this; | |
| 134 | |
| 135 if (!_sources[id.source].isResolved(id)) { | |
| 136 throw new ArgumentError('ID "$id" is not resolved.'); | |
| 137 } | |
| 138 | |
| 139 var packages = new Map.from(this.packages); | |
| 140 packages[id.name] = id; | |
| 141 return new LockFile._(packages, _sources); | |
| 142 } | |
| 143 | |
| 144 /// Returns a copy of this LockFile with a package named [name] removed. | |
| 145 /// | |
| 146 /// Returns an identical [LockFile] if there's no package named [name]. | |
| 147 LockFile removePackage(String name) { | |
| 148 if (!this.packages.containsKey(name)) return this; | |
| 149 | |
| 150 var packages = new Map.from(this.packages); | |
| 151 packages.remove(name); | |
| 152 return new LockFile._(packages, _sources); | |
| 153 } | |
| 154 | |
| 112 /// Returns the serialized YAML text of the lock file. | 155 /// Returns the serialized YAML text of the lock file. |
| 113 /// | 156 /// |
| 114 /// [packageDir] is the containing directory of the root package, used to | 157 /// [packageDir] is the containing directory of the root package, used to |
| 115 /// properly serialize package descriptions. | 158 /// properly serialize package descriptions. |
| 116 String serialize(String packageDir, SourceRegistry sources) { | 159 String serialize(String packageDir) { |
| 117 // Convert the dependencies to a simple object. | 160 // Convert the dependencies to a simple object. |
| 118 var data = {}; | 161 var data = {}; |
| 119 packages.forEach((name, package) { | 162 packages.forEach((name, package) { |
| 120 var description = sources[package.source].serializeDescription(packageDir, | 163 var description = _sources[package.source] |
| 121 package.description); | 164 .serializeDescription(packageDir, package.description); |
| 122 | 165 |
| 123 data[name] = { | 166 data[name] = { |
| 124 'version': package.version.toString(), | 167 'version': package.version.toString(), |
| 125 'source': package.source, | 168 'source': package.source, |
| 126 'description': description | 169 'description': description |
| 127 }; | 170 }; |
| 128 }); | 171 }); |
| 129 | 172 |
| 130 return """ | 173 return """ |
| 131 # Generated by pub | 174 # Generated by pub |
| 132 # See http://pub.dartlang.org/doc/glossary.html#lockfile | 175 # See http://pub.dartlang.org/doc/glossary.html#lockfile |
| 133 ${yamlToString({'packages': data})} | 176 ${yamlToString({'packages': data})} |
| 134 """; | 177 """; |
| 135 } | 178 } |
| 136 } | 179 } |
| OLD | NEW |