| OLD | NEW | 
 | (Empty) | 
|    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 |  | 
|    3 // BSD-style license that can be found in the LICENSE file. |  | 
|    4  |  | 
|    5 library path_source; |  | 
|    6  |  | 
|    7 import 'dart:async'; |  | 
|    8 import 'dart:io'; |  | 
|    9  |  | 
|   10 import 'package:pathos/path.dart' as path; |  | 
|   11  |  | 
|   12 import 'log.dart' as log; |  | 
|   13  |  | 
|   14 import 'io.dart'; |  | 
|   15 import 'package.dart'; |  | 
|   16 import 'pubspec.dart'; |  | 
|   17 import 'version.dart'; |  | 
|   18 import 'source.dart'; |  | 
|   19 import 'utils.dart'; |  | 
|   20  |  | 
|   21 // TODO(rnystrom): Support relative paths. (See comment in _validatePath().) |  | 
|   22 /// A package [Source] that installs packages from a given local file path. |  | 
|   23 class PathSource extends Source { |  | 
|   24   final name = 'path'; |  | 
|   25   final shouldCache = false; |  | 
|   26  |  | 
|   27   Future<Pubspec> describe(PackageId id) { |  | 
|   28     return new Future.sync(() { |  | 
|   29       _validatePath(id.name, id.description); |  | 
|   30       return new Pubspec.load(id.name, id.description["path"], |  | 
|   31           systemCache.sources); |  | 
|   32     }); |  | 
|   33   } |  | 
|   34  |  | 
|   35   bool descriptionsEqual(description1, description2) { |  | 
|   36     try { |  | 
|   37       // Compare real paths after normalizing and resolving symlinks. |  | 
|   38       var path1 = new File(description1["path"]).fullPathSync(); |  | 
|   39       var path2 = new File(description2["path"]).fullPathSync(); |  | 
|   40       return path1 == path2; |  | 
|   41     } on FileIOException catch (ex) { |  | 
|   42       // If either of the files couldn't be found, fall back to just comparing |  | 
|   43       // the normalized paths. |  | 
|   44       var path1 = path.normalize(path.absolute(description1["path"])); |  | 
|   45       var path2 = path.normalize(path.absolute(description2["path"])); |  | 
|   46       return path1 == path2; |  | 
|   47     } |  | 
|   48   } |  | 
|   49  |  | 
|   50   Future<bool> install(PackageId id, String destination) { |  | 
|   51     return new Future.sync(() { |  | 
|   52       try { |  | 
|   53         _validatePath(id.name, id.description); |  | 
|   54       } on FormatException catch(err) { |  | 
|   55         return false; |  | 
|   56       } |  | 
|   57  |  | 
|   58       createPackageSymlink(id.name, id.description["path"], destination, |  | 
|   59           relative: id.description["relative"]); |  | 
|   60       return true; |  | 
|   61     }); |  | 
|   62   } |  | 
|   63  |  | 
|   64   /// Parses a path dependency. This takes in a path string and returns a map. |  | 
|   65   /// The "path" key will be the original path but resolved relative to the |  | 
|   66   /// containing path. The "relative" key will be `true` if the original path |  | 
|   67   /// was relative. |  | 
|   68   /// |  | 
|   69   /// A path coming from a pubspec is a simple string. From a lock file, it's |  | 
|   70   /// an expanded {"path": ..., "relative": ...} map. |  | 
|   71   dynamic parseDescription(String containingPath, description, |  | 
|   72                            {bool fromLockFile: false}) { |  | 
|   73     if (fromLockFile) { |  | 
|   74       if (description is! Map) { |  | 
|   75         throw new FormatException("The description must be a map."); |  | 
|   76       } |  | 
|   77  |  | 
|   78       if (description["path"] is! String) { |  | 
|   79         throw new FormatException("The 'path' field of the description must " |  | 
|   80             "be a string."); |  | 
|   81       } |  | 
|   82  |  | 
|   83       if (description["relative"] is! bool) { |  | 
|   84         throw new FormatException("The 'relative' field of the description " |  | 
|   85             "must be a boolean."); |  | 
|   86       } |  | 
|   87  |  | 
|   88       return description; |  | 
|   89     } |  | 
|   90  |  | 
|   91     if (description is! String) { |  | 
|   92       throw new FormatException("The description must be a path string."); |  | 
|   93     } |  | 
|   94  |  | 
|   95     // Resolve the path relative to the containing file path, and remember |  | 
|   96     // whether the original path was relative or absolute. |  | 
|   97     bool isRelative = path.isRelative(description); |  | 
|   98     if (path.isRelative(description)) { |  | 
|   99       // Can't handle relative paths coming from pubspecs that are not on the |  | 
|  100       // local file system. |  | 
|  101       assert(containingPath != null); |  | 
|  102  |  | 
|  103       description = path.join(path.dirname(containingPath), description); |  | 
|  104     } |  | 
|  105  |  | 
|  106     return { |  | 
|  107       "path": description, |  | 
|  108       "relative": isRelative |  | 
|  109     }; |  | 
|  110   } |  | 
|  111  |  | 
|  112   /// Ensures that [description] is a valid path description. It must be a map, |  | 
|  113   /// with a "path" key containing a path that points to an existing directory. |  | 
|  114   /// Throws a [FormatException] if the path is invalid. |  | 
|  115   void _validatePath(String name, description) { |  | 
|  116     var dir = description["path"]; |  | 
|  117  |  | 
|  118     if (dirExists(dir)) return; |  | 
|  119  |  | 
|  120     if (fileExists(dir)) { |  | 
|  121       throw new FormatException( |  | 
|  122           "Path dependency for package '$name' must refer to a " |  | 
|  123           "directory, not a file. Was '$dir'."); |  | 
|  124     } |  | 
|  125  |  | 
|  126     throw new FormatException("Could not find package '$name' at '$dir'."); |  | 
|  127   } |  | 
|  128 } |  | 
| OLD | NEW |