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

Side by Side Diff: lib/packages_file.dart

Issue 1142363005: Added .packages, packages/ discovery. (Closed) Base URL: https://github.com/dart-lang/package_config.git@master
Patch Set: Addressed comments. Created 5 years, 7 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
« no previous file with comments | « lib/packages.dart ('k') | lib/src/packages_impl.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 library package_config.packages_file;
6
7 import "package:charcode/ascii.dart";
8 import "src/util.dart" show isIdentifier;
9
10 /// Parses a `.packages` file into a map from package name to base URI.
11 ///
12 /// The [source] is the byte content of a `.packages` file, assumed to be
13 /// UTF-8 encoded. In practice, all sinficant parts of the file must be ASCII,
14 /// so Latin-1 or Windows-1252 encoding will also work fine.
15 ///
16 /// If the file content is available as a string, its [String.codeUnits] can
17 /// be used as the `source` argument of this function.
18 ///
19 /// The [baseLocation] is used as a base URI to resolve all relative
20 /// URI references against.
21 /// If the content was read from a file, `baseLocation` should be the
22 /// location of that file.
23 ///
24 /// Returns a simple mapping from package name to package location.
25 Map<String, Uri> parse(List<int> source, Uri baseLocation) {
26 int index = 0;
27 Map<String, Uri> result = <String, Uri>{};
28 while (index < source.length) {
29 bool isComment = false;
30 int start = index;
31 int eqIndex = -1;
32 int end = source.length;
33 int char = source[index++];
34 if (char == $cr || char == $lf) {
35 continue;
36 }
37 if (char == $equal) {
38 throw new FormatException("Missing package name", source, index - 1);
39 }
40 isComment = char == $hash;
41 while (index < source.length) {
42 char = source[index++];
43 if (char == $equal && eqIndex < 0) {
44 eqIndex = index - 1;
45 } else if (char == $cr || char == $lf) {
46 end = index - 1;
47 break;
48 }
49 }
50 if (isComment) continue;
51 if (eqIndex < 0) {
52 throw new FormatException("No '=' on line", source, index - 1);
53 }
54 var packageName = new String.fromCharCodes(source, start, eqIndex);
55 if (!isIdentifier(packageName)) {
56 throw new FormatException("Not a valid package name", packageName, 0);
57 }
58 var packageUri = new String.fromCharCodes(source, eqIndex + 1, end);
59 var packageLocation = Uri.parse(packageUri);
60 if (!packageLocation.path.endsWith('/')) {
61 packageLocation =
62 packageLocation.replace(path: packageLocation.path + "/");
63 }
64 packageLocation = baseLocation.resolveUri(packageLocation);
65 if (result.containsKey(packageName)) {
66 throw new FormatException(
67 "Same package name occured twice.", source, start);
68 }
69 result[packageName] = packageLocation;
70 }
71 return result;
72 }
73
74 /// Writes the mapping to a [StringSink].
75 ///
76 /// If [comment] is provided, the output will contain this comment
77 /// with `#` in front of each line.
78 ///
79 /// If [baseUri] is provided, package locations will be made relative
80 /// to the base URI, if possible, before writing.
81 void write(StringSink output, Map<String, Uri> packageMapping,
82 {Uri baseUri, String comment}) {
83 if (baseUri != null && !baseUri.isAbsolute) {
84 throw new ArgumentError.value(baseUri, "baseUri", "Must be absolute");
85 }
86
87 if (comment != null) {
88 for (var commentLine in comment.split('\n')) {
89 output.write('#');
90 output.writeln(commentLine);
91 }
92 } else {
93 output.write("# generated by package:package_config at ");
94 output.write(new DateTime.now());
95 output.writeln();
96 }
97
98 packageMapping.forEach((String packageName, Uri uri) {
99 // Validate packageName.
100 if (!isIdentifier(packageName)) {
101 throw new ArgumentError('"$packageName" is not a valid package name');
102 }
103 output.write(packageName);
104 output.write('=');
105 // If baseUri provided, make uri relative.
106 if (baseUri != null) {
107 uri = _relativize(uri, baseUri);
108 }
109 output.write(uri);
110 if (!uri.path.endsWith('/')) {
111 output.write('/');
112 }
113 output.writeln();
114 });
115 }
116
117 /// Attempts to return a relative URI for [uri].
118 ///
119 /// The result URI satisfies `baseUri.resolveUri(result) == uri`,
120 /// but may be relative.
121 /// The `baseUri` must be absolute.
122 Uri _relativize(Uri uri, Uri baseUri) {
123 assert(!baseUri.isAbsolute);
124 if (uri.hasQuery || uri.hasFragment) {
125 uri = new Uri(
126 scheme: uri.scheme,
127 userInfo: uri.hasAuthority ? uri.userInfo : null,
128 host: uri.hasAuthority ? uri.host : null,
129 port: uri.hasAuthority ? uri.port : null,
130 path: uri.path);
131 }
132
133 // Already relative. We assume the caller knows what they are doing.
134 if (!uri.isAbsolute) return uri;
135
136 if (baseUri.scheme != uri.scheme) {
137 return uri;
138 }
139
140 // If authority differs, we could remove the scheme, but it's not worth it.
141 if (uri.hasAuthority != baseUri.hasAuthority) return uri;
142 if (uri.hasAuthority) {
143 if (uri.userInfo != baseUri.userInfo ||
144 uri.host.toLowerCase() != baseUri.host.toLowerCase() ||
145 uri.port != baseUri.port) {
146 return uri;
147 }
148 }
149
150 baseUri = baseUri.normalizePath();
151 List<String> base = baseUri.pathSegments.toList();
152 if (base.isNotEmpty) {
153 base = new List<String>.from(base)..removeLast();
154 }
155 uri = uri.normalizePath();
156 List<String> target = uri.pathSegments.toList();
157 int index = 0;
158 while (index < base.length && index < target.length) {
159 if (base[index] != target[index]) {
160 break;
161 }
162 index++;
163 }
164 if (index == base.length) {
165 return new Uri(path: target.skip(index).join('/'));
166 } else if (index > 0) {
167 return new Uri(
168 path: '../' * (base.length - index) + target.skip(index).join('/'));
169 } else {
170 return uri;
171 }
172 }
OLDNEW
« no previous file with comments | « lib/packages.dart ('k') | lib/src/packages_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698