Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: sdk/lib/_internal/pub/lib/src/pubspec.dart

Issue 16351003: Move pub over to using the pub.dartlang.org API v2. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 pubspec; 5 library pubspec;
6 6
7 import 'package:yaml/yaml.dart'; 7 import 'package:yaml/yaml.dart';
8 import 'package:pathos/path.dart' as path; 8 import 'package:pathos/path.dart' as path;
9 9
10 import 'io.dart'; 10 import 'io.dart';
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 version = Version.none, 67 version = Version.none,
68 dependencies = <PackageDep>[], 68 dependencies = <PackageDep>[],
69 devDependencies = <PackageDep>[], 69 devDependencies = <PackageDep>[],
70 environment = new PubspecEnvironment(), 70 environment = new PubspecEnvironment(),
71 fields = {}; 71 fields = {};
72 72
73 /// Whether or not the pubspec has no contents. 73 /// Whether or not the pubspec has no contents.
74 bool get isEmpty => 74 bool get isEmpty =>
75 name == null && version == Version.none && dependencies.isEmpty; 75 name == null && version == Version.none && dependencies.isEmpty;
76 76
77 /// Returns a Pubspec object for an already-parsed map representing its
78 /// contents.
79 ///
80 /// This will validate that [contents] is a valid pubspec.
81 factory Pubspec.fromMap(Map contents, SourceRegistry sources) =>
82 _parseMap(null, contents, sources);
83
77 // TODO(rnystrom): Instead of allowing a null argument here, split this up 84 // TODO(rnystrom): Instead of allowing a null argument here, split this up
78 // into load(), parse(), and _parse() like LockFile does. 85 // into load(), parse(), and _parse() like LockFile does.
79 /// Parses the pubspec stored at [filePath] whose text is [contents]. If the 86 /// Parses the pubspec stored at [filePath] whose text is [contents]. If the
80 /// pubspec doesn't define version for itself, it defaults to [Version.none]. 87 /// pubspec doesn't define version for itself, it defaults to [Version.none].
81 /// [filePath] may be `null` if the pubspec is not on the user's local 88 /// [filePath] may be `null` if the pubspec is not on the user's local
82 /// file system. 89 /// file system.
83 factory Pubspec.parse(String filePath, String contents, 90 factory Pubspec.parse(String filePath, String contents,
84 SourceRegistry sources) { 91 SourceRegistry sources) {
85 var name = null;
86 var version = Version.none;
87
88 if (contents.trim() == '') return new Pubspec.empty(); 92 if (contents.trim() == '') return new Pubspec.empty();
89 93
90 var parsedPubspec = loadYaml(contents); 94 var parsedPubspec = loadYaml(contents);
91 if (parsedPubspec == null) return new Pubspec.empty(); 95 if (parsedPubspec == null) return new Pubspec.empty();
92 96
93 if (parsedPubspec is! Map) { 97 if (parsedPubspec is! Map) {
94 throw new FormatException('The pubspec must be a YAML mapping.'); 98 throw new FormatException('The pubspec must be a YAML mapping.');
95 } 99 }
96 100
97 if (parsedPubspec.containsKey('name')) { 101 return _parseMap(filePath, parsedPubspec, sources);
98 name = parsedPubspec['name'];
99 if (name is! String) {
100 throw new FormatException(
101 'The pubspec "name" field should be a string, but was "$name".');
102 }
103 }
104
105 if (parsedPubspec.containsKey('version')) {
106 version = new Version.parse(parsedPubspec['version']);
107 }
108
109 var dependencies = _parseDependencies(filePath, sources,
110 parsedPubspec['dependencies']);
111
112 var devDependencies = _parseDependencies(filePath, sources,
113 parsedPubspec['dev_dependencies']);
114
115 // Make sure the same package doesn't appear as both a regular and dev
116 // dependency.
117 var dependencyNames = dependencies.map((dep) => dep.name).toSet();
118 var collisions = dependencyNames.intersection(
119 devDependencies.map((dep) => dep.name).toSet());
120
121 if (!collisions.isEmpty) {
122 var packageNames;
123 if (collisions.length == 1) {
124 packageNames = 'Package "${collisions.first}"';
125 } else {
126 var names = collisions.toList();
127 names.sort();
128 var buffer = new StringBuffer();
129 buffer.write("Packages ");
130 for (var i = 0; i < names.length; i++) {
131 buffer.write('"');
132 buffer.write(names[i]);
133 buffer.write('"');
134 if (i == names.length - 2) {
135 buffer.write(", ");
136 } else if (i == names.length - 1) {
137 buffer.write(", and ");
138 }
139 }
140
141 packageNames = buffer.toString();
142 }
143 throw new FormatException(
144 '$packageNames cannot appear in both "dependencies" and '
145 '"dev_dependencies".');
146 }
147
148 var environmentYaml = parsedPubspec['environment'];
149 var sdkConstraint = VersionConstraint.any;
150 if (environmentYaml != null) {
151 if (environmentYaml is! Map) {
152 throw new FormatException(
153 'The pubspec "environment" field should be a map, but was '
154 '"$environmentYaml".');
155 }
156
157 var sdkYaml = environmentYaml['sdk'];
158 if (sdkYaml is! String) {
159 throw new FormatException(
160 'The "sdk" field of "environment" should be a string, but was '
161 '"$sdkYaml".');
162 }
163
164 sdkConstraint = new VersionConstraint.parse(sdkYaml);
165 }
166 var environment = new PubspecEnvironment(sdkConstraint);
167
168 // Even though the pub app itself doesn't use these fields, we validate
169 // them here so that users find errors early before they try to upload to
170 // the server:
171 // TODO(rnystrom): We should split this validation into separate layers:
172 // 1. Stuff that is required in any pubspec to perform any command. Things
173 // like "must have a name". That should go here.
174 // 2. Stuff that is required to upload a package. Things like "homepage
175 // must use a valid scheme". That should go elsewhere. pub upload should
176 // call it, and we should provide a separate command to show the user,
177 // and also expose it to the editor in some way.
178
179 if (parsedPubspec.containsKey('homepage')) {
180 _validateFieldUrl(parsedPubspec['homepage'], 'homepage');
181 }
182 if (parsedPubspec.containsKey('documentation')) {
183 _validateFieldUrl(parsedPubspec['documentation'], 'documentation');
184 }
185
186 if (parsedPubspec.containsKey('author') &&
187 parsedPubspec['author'] is! String) {
188 throw new FormatException(
189 'The "author" field should be a string, but was '
190 '${parsedPubspec["author"]}.');
191 }
192
193 if (parsedPubspec.containsKey('authors')) {
194 var authors = parsedPubspec['authors'];
195 if (authors is List) {
196 // All of the elements must be strings.
197 if (!authors.every((author) => author is String)) {
198 throw new FormatException('The "authors" field should be a string '
199 'or a list of strings, but was "$authors".');
200 }
201 } else if (authors is! String) {
202 throw new FormatException('The pubspec "authors" field should be a '
203 'string or a list of strings, but was "$authors".');
204 }
205
206 if (parsedPubspec.containsKey('author')) {
207 throw new FormatException('A pubspec should not have both an "author" '
208 'and an "authors" field.');
209 }
210 }
211
212 return new Pubspec(name, version, dependencies, devDependencies,
213 environment, parsedPubspec);
214 } 102 }
215 } 103 }
216 104
217 /// Evaluates whether the given [url] for [field] is valid. 105 /// Evaluates whether the given [url] for [field] is valid.
218 /// 106 ///
219 /// Throws [FormatException] on an invalid url. 107 /// Throws [FormatException] on an invalid url.
220 void _validateFieldUrl(url, String field) { 108 void _validateFieldUrl(url, String field) {
221 if (url is! String) { 109 if (url is! String) {
222 throw new FormatException( 110 throw new FormatException(
223 'The "$field" field should be a string, but was "$url".'); 111 'The "$field" field should be a string, but was "$url".');
224 } 112 }
225 113
226 var goodScheme = new RegExp(r'^https?:'); 114 var goodScheme = new RegExp(r'^https?:');
227 if (!goodScheme.hasMatch(url)) { 115 if (!goodScheme.hasMatch(url)) {
228 throw new FormatException( 116 throw new FormatException(
229 'The "$field" field should be an "http:" or "https:" URL, but ' 117 'The "$field" field should be an "http:" or "https:" URL, but '
230 'was "$url".'); 118 'was "$url".');
231 } 119 }
232 } 120 }
233 121
122 Pubspec _parseMap(String filePath, Map map, SourceRegistry sources) {
123 var name = null;
124 var version = Version.none;
125
126 if (map.containsKey('name')) {
127 name = map['name'];
128 if (name is! String) {
129 throw new FormatException(
130 'The pubspec "name" field should be a string, but was "$name".');
131 }
132 }
133
134 if (map.containsKey('version')) {
135 version = new Version.parse(map['version']);
136 }
137
138 var dependencies = _parseDependencies(filePath, sources,
139 map['dependencies']);
140
141 var devDependencies = _parseDependencies(filePath, sources,
142 map['dev_dependencies']);
143
144 // Make sure the same package doesn't appear as both a regular and dev
145 // dependency.
146 var dependencyNames = dependencies.map((dep) => dep.name).toSet();
147 var collisions = dependencyNames.intersection(
148 devDependencies.map((dep) => dep.name).toSet());
149
150 if (!collisions.isEmpty) {
151 var packageNames;
152 if (collisions.length == 1) {
153 packageNames = 'Package "${collisions.first}"';
154 } else {
155 var names = collisions.toList();
156 names.sort();
157 var buffer = new StringBuffer();
158 buffer.write("Packages ");
159 for (var i = 0; i < names.length; i++) {
160 buffer.write('"');
161 buffer.write(names[i]);
162 buffer.write('"');
163 if (i == names.length - 2) {
164 buffer.write(", ");
165 } else if (i == names.length - 1) {
166 buffer.write(", and ");
167 }
168 }
169
170 packageNames = buffer.toString();
171 }
172 throw new FormatException(
173 '$packageNames cannot appear in both "dependencies" and '
174 '"dev_dependencies".');
175 }
176
177 var environmentYaml = map['environment'];
178 var sdkConstraint = VersionConstraint.any;
179 if (environmentYaml != null) {
180 if (environmentYaml is! Map) {
181 throw new FormatException(
182 'The pubspec "environment" field should be a map, but was '
183 '"$environmentYaml".');
184 }
185
186 var sdkYaml = environmentYaml['sdk'];
187 if (sdkYaml is! String) {
188 throw new FormatException(
189 'The "sdk" field of "environment" should be a string, but was '
190 '"$sdkYaml".');
191 }
192
193 sdkConstraint = new VersionConstraint.parse(sdkYaml);
194 }
195 var environment = new PubspecEnvironment(sdkConstraint);
196
197 // Even though the pub app itself doesn't use these fields, we validate
198 // them here so that users find errors early before they try to upload to
199 // the server:
200 // TODO(rnystrom): We should split this validation into separate layers:
201 // 1. Stuff that is required in any pubspec to perform any command. Things
202 // like "must have a name". That should go here.
203 // 2. Stuff that is required to upload a package. Things like "homepage
204 // must use a valid scheme". That should go elsewhere. pub upload should
205 // call it, and we should provide a separate command to show the user,
206 // and also expose it to the editor in some way.
207
208 if (map.containsKey('homepage')) {
209 _validateFieldUrl(map['homepage'], 'homepage');
210 }
211 if (map.containsKey('documentation')) {
212 _validateFieldUrl(map['documentation'], 'documentation');
213 }
214
215 if (map.containsKey('author') && map['author'] is! String) {
216 throw new FormatException(
217 'The "author" field should be a string, but was '
218 '${map["author"]}.');
219 }
220
221 if (map.containsKey('authors')) {
222 var authors = map['authors'];
223 if (authors is List) {
224 // All of the elements must be strings.
225 if (!authors.every((author) => author is String)) {
226 throw new FormatException('The "authors" field should be a string '
227 'or a list of strings, but was "$authors".');
228 }
229 } else if (authors is! String) {
230 throw new FormatException('The pubspec "authors" field should be a '
231 'string or a list of strings, but was "$authors".');
232 }
233
234 if (map.containsKey('author')) {
235 throw new FormatException('A pubspec should not have both an "author" '
236 'and an "authors" field.');
237 }
238 }
239
240 return new Pubspec(name, version, dependencies, devDependencies,
241 environment, map);
242 }
243
234 List<PackageDep> _parseDependencies(String pubspecPath, SourceRegistry sources, 244 List<PackageDep> _parseDependencies(String pubspecPath, SourceRegistry sources,
235 yaml) { 245 yaml) {
236 var dependencies = <PackageDep>[]; 246 var dependencies = <PackageDep>[];
237 247
238 // Allow an empty dependencies key. 248 // Allow an empty dependencies key.
239 if (yaml == null) return dependencies; 249 if (yaml == null) return dependencies;
240 250
241 if (yaml is! Map || yaml.keys.any((e) => e is! String)) { 251 if (yaml is! Map || yaml.keys.any((e) => e is! String)) {
242 throw new FormatException( 252 throw new FormatException(
243 'The pubspec dependencies should be a map of package names, but ' 253 'The pubspec dependencies should be a map of package names, but '
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 /// The environment-related metadata in the pubspec. Corresponds to the data 306 /// The environment-related metadata in the pubspec. Corresponds to the data
297 /// under the "environment:" key in the pubspec. 307 /// under the "environment:" key in the pubspec.
298 class PubspecEnvironment { 308 class PubspecEnvironment {
299 /// The version constraint specifying which SDK versions this package works 309 /// The version constraint specifying which SDK versions this package works
300 /// with. 310 /// with.
301 final VersionConstraint sdkVersion; 311 final VersionConstraint sdkVersion;
302 312
303 PubspecEnvironment([VersionConstraint sdk]) 313 PubspecEnvironment([VersionConstraint sdk])
304 : sdkVersion = sdk != null ? sdk : VersionConstraint.any; 314 : sdkVersion = sdk != null ? sdk : VersionConstraint.any;
305 } 315 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698