OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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.source.path; | 5 library pub.source.path; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:path/path.dart' as p; | 9 import 'package:path/path.dart' as p; |
| 10 import 'package:pub_semver/pub_semver.dart'; |
10 | 11 |
11 import '../exceptions.dart'; | 12 import '../exceptions.dart'; |
12 import '../io.dart'; | 13 import '../io.dart'; |
13 import '../package.dart'; | 14 import '../package.dart'; |
14 import '../pubspec.dart'; | 15 import '../pubspec.dart'; |
15 import '../source.dart'; | 16 import '../source.dart'; |
16 import '../utils.dart'; | 17 import '../utils.dart'; |
17 | 18 |
18 /// A package [Source] that gets packages from a given local file path. | 19 /// A package [Source] that gets packages from a given local file path. |
19 class PathSource extends Source { | 20 class PathSource extends Source { |
20 /// Returns a valid description for a reference to a package at [path]. | 21 /// Returns a reference to a path package named [name] at [path]. |
21 static describePath(String path) { | 22 static PackageRef refFor(String name, String path) { |
22 return { | 23 return new PackageRef(name, 'path', { |
23 "path": path, | 24 "path": path, |
24 "relative": p.isRelative(path) | 25 "relative": p.isRelative(path) |
25 }; | 26 }); |
| 27 } |
| 28 |
| 29 /// Returns an ID for a path package with the given [name] and [version] at |
| 30 /// [path]. |
| 31 static PackageId idFor(String name, Version version, String path) { |
| 32 return new PackageId(name, 'path', version, { |
| 33 "path": path, |
| 34 "relative": p.isRelative(path) |
| 35 }); |
26 } | 36 } |
27 | 37 |
28 /// Given a valid path reference description, returns the file path it | 38 /// Given a valid path reference description, returns the file path it |
29 /// describes. | 39 /// describes. |
30 /// | 40 /// |
31 /// This returned path may be relative or absolute and it is up to the caller | 41 /// This returned path may be relative or absolute and it is up to the caller |
32 /// to know how to interpret a relative path. | 42 /// to know how to interpret a relative path. |
33 static String pathFromDescription(description) => description["path"]; | 43 static String pathFromDescription(description) => description["path"]; |
34 | 44 |
35 final name = 'path'; | 45 final name = 'path'; |
36 | 46 |
37 Future<Pubspec> doDescribe(PackageId id) { | 47 Future<List<PackageId>> doGetVersions(PackageRef ref) async { |
38 return new Future.sync(() { | 48 // There's only one package ID for a given path. We just need to find the |
39 var dir = _validatePath(id.name, id.description); | 49 // version. |
40 return new Pubspec.load(dir, systemCache.sources, | 50 var pubspec = _loadPubspec(ref); |
41 expectedName: id.name); | 51 var id = new PackageId(ref.name, name, pubspec.version, ref.description); |
42 }); | 52 memoizePubspec(id, pubspec); |
| 53 return [id]; |
| 54 } |
| 55 |
| 56 Future<Pubspec> doDescribe(PackageId id) async => _loadPubspec(id.toRef()); |
| 57 |
| 58 Pubspec _loadPubspec(PackageRef ref) { |
| 59 var dir = _validatePath(ref.name, ref.description); |
| 60 return new Pubspec.load(dir, systemCache.sources, |
| 61 expectedName: ref.name); |
43 } | 62 } |
44 | 63 |
45 bool descriptionsEqual(description1, description2) { | 64 bool descriptionsEqual(description1, description2) { |
46 // Compare real paths after normalizing and resolving symlinks. | 65 // Compare real paths after normalizing and resolving symlinks. |
47 var path1 = canonicalize(description1["path"]); | 66 var path1 = canonicalize(description1["path"]); |
48 var path2 = canonicalize(description2["path"]); | 67 var path2 = canonicalize(description2["path"]); |
49 return path1 == path2; | 68 return path1 == path2; |
50 } | 69 } |
51 | 70 |
52 Future get(PackageId id, String symlink) { | 71 Future get(PackageId id, String symlink) { |
53 return new Future.sync(() { | 72 return new Future.sync(() { |
54 var dir = _validatePath(id.name, id.description); | 73 var dir = _validatePath(id.name, id.description); |
55 createPackageSymlink(id.name, dir, symlink, | 74 createPackageSymlink(id.name, dir, symlink, |
56 relative: id.description["relative"]); | 75 relative: id.description["relative"]); |
57 }); | 76 }); |
58 } | 77 } |
59 | 78 |
60 String getDirectory(PackageId id) => id.description["path"]; | 79 String getDirectory(PackageId id) => id.description["path"]; |
61 | 80 |
62 /// Parses a path dependency. | 81 /// Parses a path dependency. |
63 /// | 82 /// |
64 /// This takes in a path string and returns a map. The "path" key will be the | 83 /// This takes in a path string and returns a map. The "path" key will be the |
65 /// original path but resolved relative to the containing path. The | 84 /// original path but resolved relative to the containing path. The |
66 /// "relative" key will be `true` if the original path was relative. | 85 /// "relative" key will be `true` if the original path was relative. |
67 /// | 86 PackageRef parseRef(String name, description, {String containingPath}) { |
68 /// A path coming from a pubspec is a simple string. From a lock file, it's | |
69 /// an expanded {"path": ..., "relative": ...} map. | |
70 dynamic parseDescription(String containingPath, description, | |
71 {bool fromLockFile: false}) { | |
72 if (fromLockFile) { | |
73 if (description is! Map) { | |
74 throw new FormatException("The description must be a map."); | |
75 } | |
76 | |
77 if (description["path"] is! String) { | |
78 throw new FormatException("The 'path' field of the description must " | |
79 "be a string."); | |
80 } | |
81 | |
82 if (description["relative"] is! bool) { | |
83 throw new FormatException("The 'relative' field of the description " | |
84 "must be a boolean."); | |
85 } | |
86 | |
87 return description; | |
88 } | |
89 | |
90 if (description is! String) { | 87 if (description is! String) { |
91 throw new FormatException("The description must be a path string."); | 88 throw new FormatException("The description must be a path string."); |
92 } | 89 } |
93 | 90 |
94 // Resolve the path relative to the containing file path, and remember | 91 // Resolve the path relative to the containing file path, and remember |
95 // whether the original path was relative or absolute. | 92 // whether the original path was relative or absolute. |
96 var isRelative = p.isRelative(description); | 93 var isRelative = p.isRelative(description); |
97 if (isRelative) { | 94 if (isRelative) { |
98 // Relative paths coming from pubspecs that are not on the local file | 95 // Relative paths coming from pubspecs that are not on the local file |
99 // system aren't allowed. This can happen if a hosted or git dependency | 96 // system aren't allowed. This can happen if a hosted or git dependency |
100 // has a path dependency. | 97 // has a path dependency. |
101 if (containingPath == null) { | 98 if (containingPath == null) { |
102 throw new FormatException('"$description" is a relative path, but this ' | 99 throw new FormatException('"$description" is a relative path, but this ' |
103 'isn\'t a local pubspec.'); | 100 'isn\'t a local pubspec.'); |
104 } | 101 } |
105 | 102 |
106 description = p.normalize( | 103 description = p.normalize( |
107 p.join(p.dirname(containingPath), description)); | 104 p.join(p.dirname(containingPath), description)); |
108 } | 105 } |
109 | 106 |
110 return { | 107 return new PackageRef(name, this.name, { |
111 "path": description, | 108 "path": description, |
112 "relative": isRelative | 109 "relative": isRelative |
113 }; | 110 }); |
| 111 } |
| 112 |
| 113 PackageId parseId(String name, Version version, description) { |
| 114 if (description is! Map) { |
| 115 throw new FormatException("The description must be a map."); |
| 116 } |
| 117 |
| 118 if (description["path"] is! String) { |
| 119 throw new FormatException("The 'path' field of the description must " |
| 120 "be a string."); |
| 121 } |
| 122 |
| 123 if (description["relative"] is! bool) { |
| 124 throw new FormatException("The 'relative' field of the description " |
| 125 "must be a boolean."); |
| 126 } |
| 127 |
| 128 return new PackageId(name, this.name, version, description); |
114 } | 129 } |
115 | 130 |
116 /// Serializes path dependency's [description]. | 131 /// Serializes path dependency's [description]. |
117 /// | 132 /// |
118 /// For the descriptions where `relative` attribute is `true`, tries to make | 133 /// For the descriptions where `relative` attribute is `true`, tries to make |
119 /// `path` relative to the specified [containingPath]. | 134 /// `path` relative to the specified [containingPath]. |
120 dynamic serializeDescription(String containingPath, description) { | 135 dynamic serializeDescription(String containingPath, description) { |
121 if (description["relative"]) { | 136 if (description["relative"]) { |
122 return { | 137 return { |
123 "path": p.relative(description['path'], from: containingPath), | 138 "path": p.relative(description['path'], from: containingPath), |
(...skipping 26 matching lines...) Expand all Loading... |
150 | 165 |
151 if (fileExists(dir)) { | 166 if (fileExists(dir)) { |
152 fail('Path dependency for package $name must refer to a directory, ' | 167 fail('Path dependency for package $name must refer to a directory, ' |
153 'not a file. Was "$dir".'); | 168 'not a file. Was "$dir".'); |
154 } | 169 } |
155 | 170 |
156 throw new PackageNotFoundException( | 171 throw new PackageNotFoundException( |
157 'Could not find package $name at "$dir".'); | 172 'Could not find package $name at "$dir".'); |
158 } | 173 } |
159 } | 174 } |
OLD | NEW |